Fixes for the move of jpa.test.query to orm.test

* Allow JdbcTypeDescriptor to resolve JavaTypeDescriptor also based on precision/scale to support resolving VARCHAR(1) to Character
* Implement support for rendering comments and hints for DML statements.
* Implement support for tuple transformer
* Apply type inference on SQM parameters and put coercion behind `isLoadByIdComplianceEnabled` consistently
* Implement native query result type validation
* Fix some temporal type related resolving issues
* Fix parameter validation issue
* Apply delayed fetch builders for implicit basic attributes for result set mappings
* Use resolved JdbcTypeDescriptor and column length/scale to resolve recommended JdbcTypeDescriptor
* Fix type resolving for composite path sources
* Make ManagedDomainType implement AllowableParameterType
* Make DiscriminatorSqmPathSource implement AllowableParameterType
* Fix some id-class related path source issues
This commit is contained in:
Christian Beikov 2021-09-27 17:53:23 +02:00
parent d4ecfbc1b8
commit f1680fabcd
86 changed files with 832 additions and 402 deletions

View File

@ -15,6 +15,7 @@ import jakarta.persistence.TemporalType;
import org.hibernate.MappingException;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.JdbcMapping;
@ -187,7 +188,28 @@ public class InferredBasicValueResolver {
if ( explicitJdbcType != null ) {
// we have an explicit STD, but no JTD - infer JTD
// - NOTE : yes its an odd case, but its easy to implement here, so...
final BasicJavaDescriptor recommendedJtd = explicitJdbcType.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
Integer length = null;
Integer scale = null;
if ( selectable instanceof Column ) {
final Column column = (Column) selectable;
if ( column.getPrecision() != null && column.getPrecision() > 0 ) {
length = column.getPrecision();
scale = column.getScale();
}
else if ( column.getLength() != null ) {
if ( column.getLength() > (long) Integer.MAX_VALUE ) {
length = Integer.MAX_VALUE;
}
else {
length = column.getLength().intValue();
}
}
}
final BasicJavaDescriptor recommendedJtd = explicitJdbcType.getJdbcRecommendedJavaTypeMapping(
length,
scale,
typeConfiguration
);
final BasicType<?> resolved = typeConfiguration.getBasicTypeRegistry().resolve(
recommendedJtd,
explicitJdbcType
@ -460,7 +482,10 @@ public class InferredBasicValueResolver {
);
}
else {
basicType = registeredType;
basicType = (BasicType) legacyTemporalType.resolveTemporalPrecision(
reflectedJtd.getPrecision(),
typeConfiguration
);
}
return new InferredBasicValueResolution(

View File

@ -37,7 +37,6 @@ public class NativeQueryInterpreterStandardImpl implements NativeQueryInterprete
queryDefinition.getAffectedTableNames(),
queryDefinition.getQueryParameterList(),
queryDefinition.getResultSetMapping(),
queryDefinition.getRowTransformer(),
sessionFactory
);
}

View File

@ -46,7 +46,6 @@ public interface NativeQueryInterpreter extends Service {
queryDefinition.getAffectedTableNames(),
queryDefinition.getQueryParameterList(),
queryDefinition.getResultSetMapping(),
queryDefinition.getRowTransformer(),
sessionFactory
);
}

View File

@ -15,6 +15,7 @@ import java.util.TimeZone;
import java.util.UUID;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.TransactionRequiredException;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
@ -52,6 +53,7 @@ import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.internal.ProcedureCallImpl;
@ -704,7 +706,12 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
try {
NativeQueryImplementor query = createNativeQuery( sqlString );
query.addEntity( "alias1", resultClass.getName(), LockMode.READ );
if ( Tuple.class.equals( resultClass ) ) {
query.setTupleTransformer( new NativeQueryTupleTransformer() );
}
else {
query.addEntity( "alias1", resultClass.getName(), LockMode.READ );
}
return query;
}
catch (RuntimeException he) {
@ -740,7 +747,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
return query;
// throw new NotYetImplementedFor6Exception( getClass() );
}

View File

@ -124,8 +124,15 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
final List<Object> idsInBatch = new ArrayList<>();
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
final boolean coerce = !sessionFactory.getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
for ( int i = 0; i < ids.length; i++ ) {
final Object id = entityDescriptor.getIdentifierMapping().getJavaTypeDescriptor().coerce( ids[i], session );
final Object id;
if ( coerce ) {
id = entityDescriptor.getIdentifierMapping().getJavaTypeDescriptor().coerce( ids[i], session );
}
else {
id = ids[i];
}
final EntityKey entityKey = new EntityKey( id, entityDescriptor );
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
@ -357,8 +364,15 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
boolean foundAnyManagedEntities = false;
final List<Object> nonManagedIds = new ArrayList<>();
final boolean coerce = !sessionFactory.getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
for ( int i = 0; i < ids.length; i++ ) {
final Object id = entityDescriptor.getIdentifierMapping().getJavaTypeDescriptor().coerce( ids[ i ], session );
final Object id;
if ( coerce ) {
id = entityDescriptor.getIdentifierMapping().getJavaTypeDescriptor().coerce( ids[i], session );
}
else {
id = ids[i];
}
final EntityKey entityKey = new EntityKey( id, entityDescriptor );
LoadEvent loadEvent = new LoadEvent(

View File

@ -410,17 +410,21 @@ public class MetadataContext {
}
}
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyNonAggregatedIdAttributes( idAttributes );
// see if it also has an IdClass (identifier-mapper)
final Component idClass = persistentClass.getIdentifierMapper();
final EmbeddableTypeImpl<?> idClassType;
if ( idClass != null ) {
applyIdClassMetadata( (Component) persistentClass.getIdentifier(), idClass );
idClassType = applyIdClassMetadata( (Component) persistentClass.getIdentifier(), idClass );
}
else {
idClassType = null;
}
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyNonAggregatedIdAttributes( idAttributes, idClassType );
}
}
private void applyIdClassMetadata(Component identifier, Component idClass) {
private EmbeddableTypeImpl<?> applyIdClassMetadata(Component identifier, Component idClass) {
final JavaTypeDescriptorRegistry registry = getTypeConfiguration()
.getJavaTypeDescriptorRegistry();
final Class<?> componentClass = identifier.getComponentClass();
@ -439,6 +443,7 @@ public class MetadataContext {
getJpaMetamodel()
);
registerEmbeddableType( embeddableType, idClass );
return embeddableType;
}
@SuppressWarnings({"unchecked", "rawtypes"})

View File

@ -144,20 +144,26 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
@SuppressWarnings( "rawtypes" )
public Object normalizeIncomingValue(Object naturalIdToLoad) {
final Object normalizedValue;
if ( naturalIdToLoad instanceof Map ) {
final Map valueMap = (Map) naturalIdToLoad;
assert valueMap.size() == 1;
assert valueMap.containsKey( getAttribute().getAttributeName() );
return getJavaTypeDescriptor().coerce( valueMap.get( getAttribute().getAttributeName() ), this );
normalizedValue = valueMap.get( getAttribute().getAttributeName() );
}
if ( naturalIdToLoad instanceof Object[] ) {
else if ( naturalIdToLoad instanceof Object[] ) {
final Object[] values = (Object[]) naturalIdToLoad;
assert values.length == 1;
return getJavaTypeDescriptor().coerce( values[0], this );
normalizedValue = values[0];
}
else {
normalizedValue = naturalIdToLoad;
}
return getJavaTypeDescriptor().coerce( naturalIdToLoad, this );
if ( getTypeConfiguration().getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
return normalizedValue;
}
return getJavaTypeDescriptor().coerce( normalizedValue, this );
}
public SingularAttributeMapping getAttribute() {

View File

@ -45,8 +45,9 @@ public abstract class AbstractIdentifiableType<J>
private SingularPersistentAttribute<J,?> id;
private Set<SingularPersistentAttribute<? super J,?>> nonAggregatedIdAttributes;
private EmbeddableDomainType<?> idClassType;
private SqmPathSource identifierDescriptor;
private SqmPathSource<?> identifierDescriptor;
private final boolean isVersioned;
@ -67,19 +68,17 @@ public abstract class AbstractIdentifiableType<J>
}
@Override
@SuppressWarnings("unchecked")
protected InFlightAccessImpl createInFlightAccess() {
return new InFlightAccessImpl( super.createInFlightAccess() );
}
@Override
@SuppressWarnings("unchecked")
public InFlightAccessImpl getInFlightAccess() {
return (InFlightAccessImpl) super.getInFlightAccess();
}
@Override
public SqmPathSource getIdentifierDescriptor() {
public SqmPathSource<?> getIdentifierDescriptor() {
return identifierDescriptor;
}
@ -96,7 +95,7 @@ public abstract class AbstractIdentifiableType<J>
@SuppressWarnings("unchecked")
public IdentifiableDomainType<? super J> getSuperType() {
// overridden simply to perform the cast
return (IdentifiableDomainType) super.getSuperType();
return (IdentifiableDomainType<? super J>) super.getSuperType();
}
@Override
@ -108,11 +107,11 @@ public abstract class AbstractIdentifiableType<J>
@SuppressWarnings({ "unchecked" })
public <Y> SingularPersistentAttribute<? super J, Y> getId(Class<Y> javaType) {
ensureNoIdClass();
SingularPersistentAttribute id = findIdAttribute();
SingularPersistentAttribute<J, ?> id = findIdAttribute();
if ( id != null ) {
checkType( id, javaType );
}
return (SingularPersistentAttribute) id;
return (SingularPersistentAttribute<? super J, Y>) id;
}
private void ensureNoIdClass() {
@ -125,16 +124,16 @@ public abstract class AbstractIdentifiableType<J>
@Override
@SuppressWarnings({"unchecked", "RedundantIfStatement"})
public SingularPersistentAttribute findIdAttribute() {
@SuppressWarnings("unchecked")
public SingularPersistentAttribute<J, ?> findIdAttribute() {
if ( id != null ) {
return id;
}
else {
if ( getSuperType() != null ) {
SingularPersistentAttribute id = getSuperType().findIdAttribute();
SingularPersistentAttribute<? super J, ?> id = getSuperType().findIdAttribute();
if ( id != null ) {
return id;
return (SingularPersistentAttribute<J, ?>) id;
}
}
}
@ -142,8 +141,7 @@ public abstract class AbstractIdentifiableType<J>
return null;
}
@SuppressWarnings("unchecked")
private void checkType(SingularPersistentAttribute attribute, Class javaType) {
private void checkType(SingularPersistentAttribute<?, ?> attribute, Class<?> javaType) {
if ( ! javaType.isAssignableFrom( attribute.getType().getJavaType() ) ) {
throw new IllegalArgumentException(
String.format(
@ -170,9 +168,9 @@ public abstract class AbstractIdentifiableType<J>
@Override
public SimpleDomainType<?> getIdType() {
final SingularPersistentAttribute id = findIdAttribute();
final SingularPersistentAttribute<J, ?> id = findIdAttribute();
if ( id != null ) {
return (SimpleDomainType<?>) id.getType();
return id.getType();
}
Set<SingularPersistentAttribute<? super J, ?>> idClassAttributes = getIdClassAttributesSafely();
@ -205,20 +203,19 @@ public abstract class AbstractIdentifiableType<J>
}
@Override
@SuppressWarnings("unchecked")
public Set<SingularAttribute<? super J, ?>> getIdClassAttributes() {
if ( !hasIdClass() ) {
throw new IllegalArgumentException( "This class [" + getJavaType() + "] does not define an IdClass" );
}
final Set<SingularPersistentAttribute<? super J,?>> attributes = new HashSet<>();
final Set<SingularAttribute<? super J, ?>> attributes = new HashSet<>();
visitIdClassAttributes( attributes::add );
if ( attributes.isEmpty() ) {
throw new IllegalArgumentException( "Unable to locate IdClass attributes [" + getJavaType() + "]" );
}
return (Set) attributes;
return attributes;
}
@Override
@ -228,6 +225,7 @@ public abstract class AbstractIdentifiableType<J>
nonAggregatedIdAttributes.forEach( attributeConsumer );
}
else if ( getSuperType() != null ) {
//noinspection rawtypes
getSuperType().visitIdClassAttributes( (Consumer) attributeConsumer );
}
}
@ -242,28 +240,28 @@ public abstract class AbstractIdentifiableType<J>
}
@Override
@SuppressWarnings({ "unchecked" })
@SuppressWarnings("unchecked")
public <Y> SingularPersistentAttribute<? super J, Y> getVersion(Class<Y> javaType) {
if ( ! hasVersionAttribute() ) {
return null;
}
SingularPersistentAttribute version = findVersionAttribute();
SingularPersistentAttribute<J, ?> version = findVersionAttribute();
if ( version != null ) {
checkType( version, javaType );
}
return (SingularPersistentAttribute) version;
return (SingularPersistentAttribute<? super J, Y>) version;
}
@Override
@SuppressWarnings("unchecked")
public SingularPersistentAttribute findVersionAttribute() {
public SingularPersistentAttribute<J, ?> findVersionAttribute() {
if ( versionAttribute != null ) {
return versionAttribute;
}
if ( getSuperType() != null ) {
return getSuperType().findVersionAttribute();
return (SingularPersistentAttribute<J, ?>) getSuperType().findVersionAttribute();
}
return null;
@ -308,22 +306,24 @@ public abstract class AbstractIdentifiableType<J>
return versionAttribute;
}
@SuppressWarnings({"rawtypes", "unchecked"})
private class InFlightAccessImpl extends AbstractManagedType.InFlightAccessImpl {
private final InFlightAccess managedTypeAccess;
private class InFlightAccessImpl extends AbstractManagedType<J>.InFlightAccessImpl {
private final InFlightAccess<J> managedTypeAccess;
private InFlightAccessImpl(InFlightAccess managedTypeAccess) {
private InFlightAccessImpl(InFlightAccess<J> managedTypeAccess) {
this.managedTypeAccess = managedTypeAccess;
}
@Override
public void applyIdAttribute(SingularPersistentAttribute idAttribute) {
public void applyIdAttribute(SingularPersistentAttribute<J, ?> idAttribute) {
AbstractIdentifiableType.this.id = idAttribute;
managedTypeAccess.addAttribute( idAttribute );
}
@Override
public void applyNonAggregatedIdAttributes(Set idAttributes) {
@SuppressWarnings("unchecked")
public void applyNonAggregatedIdAttributes(
Set<SingularPersistentAttribute<? super J, ?>> idAttributes,
EmbeddableDomainType<?> idClassType) {
if ( AbstractIdentifiableType.this.id != null ) {
throw new IllegalArgumentException( "`AbstractIdentifiableType#id` already set on call to `#applyNonAggregatedIdAttribute`" );
}
@ -336,31 +336,30 @@ public abstract class AbstractIdentifiableType<J>
AbstractIdentifiableType.this.nonAggregatedIdAttributes = Collections.EMPTY_SET;
}
else {
for ( SingularPersistentAttribute idAttribute : (Set<SingularPersistentAttribute>) idAttributes ) {
for ( SingularPersistentAttribute<? super J, ?> idAttribute : idAttributes ) {
if ( AbstractIdentifiableType.this == idAttribute.getDeclaringType() ) {
addAttribute( idAttribute );
addAttribute( (PersistentAttribute<J, ?>) idAttribute );
}
}
AbstractIdentifiableType.this.nonAggregatedIdAttributes = (Set) idAttributes;
AbstractIdentifiableType.this.nonAggregatedIdAttributes = idAttributes;
}
AbstractIdentifiableType.this.idClassType = idClassType;
}
@Override
public void applyIdClassAttributes(Set idClassAttributes) {
applyNonAggregatedIdAttributes( idClassAttributes );
public void applyIdClassAttributes(Set<SingularPersistentAttribute<? super J, ?>> idClassAttributes) {
applyNonAggregatedIdAttributes( idClassAttributes, null );
}
@Override
@SuppressWarnings("unchecked")
public void applyVersionAttribute(SingularPersistentAttribute versionAttribute) {
public void applyVersionAttribute(SingularPersistentAttribute<J, ?> versionAttribute) {
AbstractIdentifiableType.this.versionAttribute = versionAttribute;
managedTypeAccess.addAttribute( versionAttribute );
}
@Override
@SuppressWarnings("unchecked")
public void addAttribute(PersistentAttribute attribute) {
public void addAttribute(PersistentAttribute<J, ?> attribute) {
managedTypeAccess.addAttribute( attribute );
}
@ -374,7 +373,7 @@ public abstract class AbstractIdentifiableType<J>
private static final Logger log = Logger.getLogger( AbstractIdentifiableType.class );
private SqmPathSource interpretIdDescriptor() {
private SqmPathSource<?> interpretIdDescriptor() {
log.tracef( "Interpreting domain-model identifier descriptor" );
if ( getSuperType() != null ) {
@ -384,18 +383,16 @@ public abstract class AbstractIdentifiableType<J>
// simple id or aggregate composite id
final SimpleDomainType<?> type = id.getType();
if ( type instanceof BasicDomainType ) {
//noinspection unchecked
return new BasicSqmPathSource(
return new BasicSqmPathSource<>(
EntityIdentifierMapping.ROLE_LOCAL_NAME,
(BasicDomainType) type,
(BasicDomainType<?>) type,
Bindable.BindableType.SINGULAR_ATTRIBUTE
);
}
else {
assert type instanceof EmbeddableDomainType;
final EmbeddableDomainType compositeType = (EmbeddableDomainType) type;
//noinspection unchecked
return new EmbeddedSqmPathSource(
final EmbeddableDomainType<?> compositeType = (EmbeddableDomainType<?>) type;
return new EmbeddedSqmPathSource<>(
EntityIdentifierMapping.ROLE_LOCAL_NAME,
compositeType,
Bindable.BindableType.SINGULAR_ATTRIBUTE
@ -404,11 +401,20 @@ public abstract class AbstractIdentifiableType<J>
}
else if ( nonAggregatedIdAttributes != null && ! nonAggregatedIdAttributes.isEmpty() ) {
// non-aggregate composite id
return new NonAggregatedCompositeSqmPathSource(
EntityIdentifierMapping.ROLE_LOCAL_NAME,
Bindable.BindableType.SINGULAR_ATTRIBUTE,
this
);
if ( idClassType == null ) {
return new NonAggregatedCompositeSqmPathSource(
EntityIdentifierMapping.ROLE_LOCAL_NAME,
Bindable.BindableType.SINGULAR_ATTRIBUTE,
this
);
}
else {
return new EmbeddedSqmPathSource<>(
EntityIdentifierMapping.ROLE_LOCAL_NAME,
idClassType,
Bindable.BindableType.SINGULAR_ATTRIBUTE
);
}
}
else {
if ( isIdMappingRequired() ) {

View File

@ -692,7 +692,7 @@ public abstract class AbstractManagedType<J>
@SuppressWarnings("unchecked")
public void addAttribute(PersistentAttribute<J,?> attribute) {
if ( attribute instanceof SingularPersistentAttribute ) {
declaredSingularAttributes.put( attribute.getName(), (SingularPersistentAttribute) attribute );
declaredSingularAttributes.put( attribute.getName(), (SingularPersistentAttribute<J, ?>) attribute );
}
else if ( attribute instanceof PluralPersistentAttribute ) {
if ( AbstractManagedType.this.declaredPluralAttributes == null ) {

View File

@ -19,7 +19,7 @@ import org.hibernate.query.sqm.SqmPathSource;
* @author Steve Ebersole
*/
public interface IdentifiableDomainType<J> extends ManagedDomainType<J>, IdentifiableType<J> {
SqmPathSource getIdentifierDescriptor();
SqmPathSource<?> getIdentifierDescriptor();
@Override
<Y> SingularPersistentAttribute<? super J, Y> getId(Class<Y> type);

View File

@ -17,7 +17,7 @@ import org.hibernate.metamodel.RepresentationMode;
*
* @author Steve Ebersole
*/
public interface ManagedDomainType<J> extends SimpleDomainType<J>, ManagedType<J> {
public interface ManagedDomainType<J> extends AllowableParameterType<J>, ManagedType<J> {
/**
* Get the type name.
*

View File

@ -9,6 +9,7 @@ package org.hibernate.metamodel.model.domain.internal;
import java.util.List;
import java.util.Set;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
@ -34,7 +35,9 @@ public interface AttributeContainer<J> {
);
}
default void applyNonAggregatedIdAttributes(Set<SingularPersistentAttribute<? super J, ?>> idAttributes) {
default void applyNonAggregatedIdAttributes(
Set<SingularPersistentAttribute<? super J, ?>> idAttributes,
EmbeddableDomainType<?> idClassType) {
throw new UnsupportedOperationException(
"AttributeContainer [" + getClass().getName() + "] does not support identifiers"
);

View File

@ -8,6 +8,8 @@ package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.sqm.SqmPathSource;
@ -18,7 +20,8 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
*
* @author Steve Ebersole
*/
public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D> {
public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
implements AllowableParameterType<D>, AllowableFunctionReturnType<D> {
private final EntityDomainType<?> entityDomainType;
private final EntityMappingType entityMapping;
@ -40,4 +43,14 @@ public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D> {
public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalStateException( "Entity discriminator cannot be de-referenced" );
}
@Override
public PersistenceType getPersistenceType() {
return PersistenceType.BASIC;
}
@Override
public Class<D> getJavaType() {
return getExpressableJavaTypeDescriptor().getJavaTypeClass();
}
}

View File

@ -45,6 +45,11 @@ public class EntityDomainResultBuilder implements ResultBuilder {
}
}
@Override
public Class<?> getJavaType() {
return entityDescriptor.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -26,6 +26,11 @@ public class ScalarDomainResultBuilder<T> implements ResultBuilder {
this.typeDescriptor = typeDescriptor;
}
@Override
public Class<?> getJavaType() {
return typeDescriptor.getJavaTypeClass();
}
@Override
public DomainResult<T> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -57,6 +57,6 @@ public abstract class AbstractQueryParameter<T> implements QueryParameterImpleme
@Override
public Class<T> getParameterType() {
return null;
return anticipatedType.getJavaType();
}
}

View File

@ -7,7 +7,7 @@
package org.hibernate.query;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
/**
* Indicates an attempt to perform some operation on a Query that is illegal
@ -16,12 +16,12 @@ import org.hibernate.HibernateException;
*
* @author Steve Ebersole
*/
public class IllegalQueryOperationException extends HibernateException {
public class IllegalQueryOperationException extends QueryException {
public IllegalQueryOperationException(String message) {
super( message );
}
public IllegalQueryOperationException(String message, Throwable cause) {
super( message, cause );
public IllegalQueryOperationException(String message, String queryString, Exception cause) {
super( message, queryString, cause );
}
}

View File

@ -13,7 +13,7 @@ import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
*
* Ultimately, gets wrapped in a
* {@link RowTransformerTupleTransformerAdapter}
* to adapt the TupleTransformer to the {@link org.hibernate.sql.exec.spi.RowTransformer}
* to adapt the TupleTransformer to the {@link org.hibernate.sql.results.spi.RowTransformer}
* contract, which is the thing actually used to process the results internally.
*
* Note that {@link JpaTupleTransformer} is a special sub-type applications may use
@ -22,7 +22,7 @@ import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
* return type as Tuple
*
* @see org.hibernate.transform.ResultTransformer
* @see org.hibernate.sql.exec.spi.RowTransformer
* @see org.hibernate.sql.results.spi.RowTransformer
*
* @author Steve Ebersole
* @author Gavin King

View File

@ -646,6 +646,7 @@ public class QuerySplitter {
return new SqmNamedParameter(
expression.getName(),
expression.allowMultiValuedBinding(),
expression.getNodeType(),
expression.nodeBuilder()
);
}

View File

@ -13,6 +13,7 @@ import java.time.ZonedDateTime;
import java.util.Calendar;
import jakarta.persistence.TemporalType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
import org.hibernate.type.CalendarDateType;
@ -23,6 +24,7 @@ import org.hibernate.type.OffsetDateTimeType;
import org.hibernate.type.OffsetTimeType;
import org.hibernate.type.TimestampType;
import org.hibernate.type.ZonedDateTimeType;
import org.hibernate.type.descriptor.java.TemporalJavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -96,6 +98,29 @@ public class BindingTypeHelper {
}
}
public JdbcMapping resolveBindType(Object value, JdbcMapping baseType) {
if ( value == null || !( baseType.getJavaTypeDescriptor() instanceof TemporalJavaTypeDescriptor<?> ) ) {
return baseType;
}
final Class<?> javaType = value.getClass();
final TemporalType temporalType = ( (TemporalJavaTypeDescriptor<?>) baseType.getJavaTypeDescriptor() ).getPrecision();
switch ( temporalType ) {
case TIMESTAMP: {
return (JdbcMapping) resolveTimestampTemporalTypeVariant( javaType, (AllowableParameterType<?>) baseType );
}
case DATE: {
return (JdbcMapping) resolveDateTemporalTypeVariant( javaType, (AllowableParameterType<?>) baseType );
}
case TIME: {
return (JdbcMapping) resolveTimeTemporalTypeVariant( javaType, (AllowableParameterType<?>) baseType );
}
default: {
throw new IllegalArgumentException( "Unexpected TemporalType [" + temporalType + "]; expecting TIMESTAMP, DATE or TIME" );
}
}
}
public AllowableParameterType resolveTimestampTemporalTypeVariant(Class javaType, AllowableParameterType baseType) {
//noinspection unchecked
if ( baseType.getExpressableJavaTypeDescriptor().getJavaTypeClass().isAssignableFrom( javaType ) ) {

View File

@ -266,6 +266,13 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
}
}
return null;
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Could not locate ordinal parameter [%s], expecting one of [%s]",
positionLabel,
StringHelper.join( ", ", labels)
)
);
}
}

View File

@ -106,11 +106,13 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
return;
}
if ( bindType != null ) {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
}
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
if ( ! getTypeConfiguration().getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
if ( bindType != null ) {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
}
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
}
}
if ( isBindingValidationRequired ) {
@ -162,11 +164,13 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
this.bindType = clarifiedType;
}
if ( bindType != null ) {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
}
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
if ( ! getTypeConfiguration().getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
if ( bindType != null ) {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
}
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
}
}
if ( isBindingValidationRequired ) {
@ -186,25 +190,27 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
bindType = queryParameter.getHibernateType();
}
if ( bindType != null ) {
try {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
if ( ! getTypeConfiguration().getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
if ( bindType != null ) {
try {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
}
catch (CoercionException ex) {
throw new IllegalArgumentException(
String.format(
"Parameter value [%s] did not match expected type [%s (%s)]",
value,
bindType.getTypeName(),
temporalTypePrecision == null ? "n/a" : temporalTypePrecision.name()
),
ex
);
}
}
catch ( CoercionException ex ) {
throw new IllegalArgumentException(
String.format(
"Parameter value [%s] did not match expected type [%s (%s)]",
value,
bindType.getTypeName(),
temporalTypePrecision == null ? "n/a" : temporalTypePrecision.name()
),
ex
);
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
}
}
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
}
if ( isBindingValidationRequired ) {
validate( value, temporalTypePrecision );

View File

@ -148,13 +148,8 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
@Override
public <P> QueryParameterBinding<P> getBinding(String name) {
final QueryParameterImplementor<?> parameter = parameterMetadata.getQueryParameter( name );
if ( parameter == null ) {
throw new IllegalArgumentException( "Parameter does not exist: " + name );
}
//noinspection unchecked
return (QueryParameterBinding<P>) getBinding( parameter );
return (QueryParameterBinding<P>) getBinding( parameterMetadata.getQueryParameter( name ) );
}
@Override

View File

@ -9,8 +9,10 @@ package org.hibernate.query.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.NavigablePath;
@ -21,6 +23,7 @@ import org.hibernate.query.results.BasicValuedFetchBuilder;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultBuilderEntityValued;
import org.hibernate.query.results.complete.CompleteResultBuilderEntityJpa;
import org.hibernate.query.results.complete.DelayedFetchBuilderBasicPart;
import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic;
/**
@ -71,12 +74,32 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento
final HashMap<String, FetchBuilder> explicitFetchBuilderMap = new HashMap<>();
explicitFetchMementoMap.forEach(
(relativePath, fetchMemento) -> explicitFetchBuilderMap.put(
relativePath,
fetchMemento.resolve(this, querySpaceConsumer, context )
)
);
// If there are no explicit fetches, we don't register DELAYED builders to get implicit fetching of all basic fetchables
if ( !explicitFetchMementoMap.isEmpty() ) {
explicitFetchMementoMap.forEach(
(relativePath, fetchMemento) -> explicitFetchBuilderMap.put(
relativePath,
fetchMemento.resolve( this, querySpaceConsumer, context )
)
);
// Implicit basic fetches are DELAYED by default, so register fetch builders for the remaining basic fetchables
entityDescriptor.visitAttributeMappings(
attributeMapping -> {
final Function<String, FetchBuilder> fetchBuilderCreator;
if ( attributeMapping instanceof BasicValuedModelPart ) {
fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart(
navigablePath.append( k ),
(BasicValuedModelPart) attributeMapping
);
explicitFetchBuilderMap.computeIfAbsent(
attributeMapping.getFetchableName(),
fetchBuilderCreator
);
}
}
);
}
return new CompleteResultBuilderEntityJpa(
navigablePath,

View File

@ -124,12 +124,12 @@ public class Builders {
public static ResultBuilderBasicValued scalar(int position) {
// will be needed for interpreting legacy HBM <resultset/> mappings
throw new NotYetImplementedFor6Exception();
return new DynamicResultBuilderBasicStandard( position );
}
public static ResultBuilderBasicValued scalar(int position, BasicType<?> type) {
// will be needed for interpreting legacy HBM <resultset/> mappings
throw new NotYetImplementedFor6Exception();
return new DynamicResultBuilderBasicStandard( position, type );
}
public static <J> DynamicResultBuilderInstantiation<J> instantiation(Class<J> targetJavaType, SessionFactoryImplementor factory) {

View File

@ -29,6 +29,8 @@ public interface ResultBuilder {
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState);
Class<?> getJavaType();
default void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
}
}

View File

@ -44,6 +44,11 @@ public class CompleteResultBuilderBasicModelPart
this.columnAlias = columnAlias;
}
@Override
public Class<?> getJavaType() {
return modelPart.getExpressableJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;

View File

@ -51,6 +51,11 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
}
@Override
public Class<?> getJavaType() {
return explicitJavaTypeDescriptor.getJavaTypeClass();
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -64,6 +64,11 @@ public class CompleteResultBuilderCollectionStandard implements CompleteResultBu
this.elementColumnNames = elementColumnNames;
}
@Override
public Class<?> getJavaType() {
return pluralAttributeDescriptor.getExpressableJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public String getTableAlias() {
return tableAlias;

View File

@ -62,6 +62,11 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti
}
}
@Override
public Class<?> getJavaType() {
return entityDescriptor.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;

View File

@ -50,6 +50,11 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
this.explicitFetchBuilderMap = explicitFetchBuilderMap;
}
@Override
public Class<?> getJavaType() {
return entityDescriptor.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;

View File

@ -39,6 +39,11 @@ public class CompleteResultBuilderInstantiation
this.argumentResultBuilders = argumentResultBuilders;
}
@Override
public Class<?> getJavaType() {
return javaTypeDescriptor.getJavaTypeClass();
}
@Override
public DomainResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -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.complete;
import java.util.function.BiFunction;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.BasicValuedFetchBuilder;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Christian Beikov
*/
public class DelayedFetchBuilderBasicPart
implements CompleteFetchBuilder, BasicValuedFetchBuilder, ModelPartReferenceBasic {
private final NavigablePath navigablePath;
private final BasicValuedModelPart referencedModelPart;
public DelayedFetchBuilderBasicPart(
NavigablePath navigablePath,
BasicValuedModelPart referencedModelPart) {
this.navigablePath = navigablePath;
this.referencedModelPart = referencedModelPart;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public BasicValuedModelPart getReferencedPart() {
return referencedModelPart;
}
@Override
public BasicFetch<?> buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
return new BasicFetch<>(
-1,
parent,
fetchPath,
referencedModelPart,
true,
null,
FetchTiming.DELAYED,
domainResultCreationState
);
}
}

View File

@ -55,6 +55,11 @@ public class DynamicResultBuilderAttribute implements DynamicResultBuilder, Nati
this.attributePath = attributePath;
}
@Override
public Class<?> getJavaType() {
return attributeMapping.getExpressableJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
throw new UnsupportedOperationException();

View File

@ -92,6 +92,11 @@ public class DynamicResultBuilderBasicConverted<O,R> implements DynamicResultBui
);
}
@Override
public Class<?> getJavaType() {
return domainJtd.getJavaTypeClass();
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -30,6 +30,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*/
public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBasic {
private final String columnName;
private final int columnPosition;
private final String resultAlias;
private final BasicType<?> explicitType;
@ -38,15 +39,27 @@ public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBa
public DynamicResultBuilderBasicStandard(String columnName, String resultAlias) {
assert columnName != null;
this.columnName = columnName;
this.columnPosition = 0;
this.resultAlias = resultAlias != null ? resultAlias : columnName;
this.explicitType = null;
this.explicitJavaTypeDescriptor = null;
}
public DynamicResultBuilderBasicStandard(int columnPosition) {
assert columnPosition > 0;
this.columnName = "c" + columnPosition;
this.columnPosition = columnPosition;
this.resultAlias = columnName;
this.explicitType = null;
this.explicitJavaTypeDescriptor = null;
}
public DynamicResultBuilderBasicStandard(String columnName, String resultAlias, JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
assert columnName != null;
this.columnName = columnName;
this.columnPosition = 0;
this.resultAlias = resultAlias != null ? resultAlias : columnName;
assert explicitJavaTypeDescriptor != null;
@ -58,6 +71,7 @@ public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBa
public DynamicResultBuilderBasicStandard(String columnName, String resultAlias, BasicType<?> explicitType) {
assert columnName != null;
this.columnName = columnName;
this.columnPosition = 0;
this.resultAlias = resultAlias != null ? resultAlias : columnName;
assert explicitType != null;
@ -66,6 +80,29 @@ public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBa
this.explicitJavaTypeDescriptor = null;
}
public DynamicResultBuilderBasicStandard(int columnPosition, BasicType<?> explicitType) {
assert columnPosition > 0;
this.columnName = "c" + columnPosition;
this.columnPosition = columnPosition;
this.resultAlias = columnName;
assert explicitType != null;
this.explicitType = explicitType;
this.explicitJavaTypeDescriptor = null;
}
@Override
public Class<?> getJavaType() {
if ( explicitJavaTypeDescriptor != null ) {
return explicitJavaTypeDescriptor.getJavaTypeClass();
}
if ( explicitType != null ) {
return explicitType.getJavaType();
}
return null;
}
public String getColumnName() {
return columnName;
}
@ -84,7 +121,13 @@ public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBa
final Expression expression = sqlExpressionResolver.resolveSqlExpression(
columnName,
state -> {
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnName );
final int jdbcPosition;
if ( columnPosition > 0 ) {
jdbcPosition = columnPosition;
}
else {
jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnName );
}
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
final BasicType<?> basicType;

View File

@ -49,6 +49,11 @@ public class DynamicResultBuilderEntityCalculated implements DynamicResultBuilde
this.sessionFactory = sessionFactory;
}
@Override
public Class<?> getJavaType() {
return entityMapping.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public EntityMappingType getEntityMapping() {
return entityMapping;

View File

@ -71,6 +71,11 @@ public class DynamicResultBuilderEntityStandard
this.tableAlias = tableAlias;
}
@Override
public Class<?> getJavaType() {
return entityMapping.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public EntityMappingType getEntityMapping() {
return entityMapping;

View File

@ -44,6 +44,11 @@ public class DynamicResultBuilderInstantiation<J>
this.javaTypeDescriptor = javaTypeDescriptor;
}
@Override
public Class<?> getJavaType() {
return javaTypeDescriptor.getJavaTypeClass();
}
@Override
public NativeQuery.InstantiationResultNode<J> addBasicArgument(String columnAlias, String argumentAlias) {
argumentResultBuilders.add(

View File

@ -32,6 +32,11 @@ public class ImplicitModelPartResultBuilderBasic
this.modelPart = modelPart;
}
@Override
public Class<?> getJavaType() {
return modelPart.getExpressableJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -37,6 +37,11 @@ public class ImplicitModelPartResultBuilderEmbeddable
this.modelPart = modelPart;
}
@Override
public Class<?> getJavaType() {
return modelPart.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public EmbeddableResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -40,6 +40,11 @@ public class ImplicitModelPartResultBuilderEntity
this( new NavigablePath( entityMappingType.getEntityName() ), entityMappingType );
}
@Override
public Class<?> getJavaType() {
return modelPart.getJavaTypeDescriptor().getJavaTypeClass();
}
@Override
public EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,

View File

@ -48,7 +48,6 @@ import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.HEMLogging;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
@ -66,7 +65,6 @@ import org.hibernate.query.TypedParameterValue;
import org.hibernate.query.internal.ScrollableResultsIterator;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.type.BasicType;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.LockMode.UPGRADE;
@ -82,7 +80,6 @@ import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
import static org.hibernate.internal.util.NullnessHelper.nullif;
import static org.hibernate.annotations.QueryHints.NATIVE_LOCKMODE;
import static org.hibernate.jpa.QueryHints.HINT_CACHEABLE;
import static org.hibernate.jpa.QueryHints.HINT_CACHE_MODE;
@ -420,8 +417,8 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
putIfNotNull( hints, HINT_CACHE_MODE, getCacheMode() );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.interpretCacheRetrieveMode( getCacheMode() ) );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_STORE_MODE, CacheModeHelper.interpretCacheStoreMode( getCacheMode() ) );
putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.interpretCacheRetrieveMode( getCacheMode() ) );
putIfNotNull( hints, JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.interpretCacheStoreMode( getCacheMode() ) );
putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, getQueryOptions().getCacheRetrieveMode() );
putIfNotNull( hints, JPA_SHARED_CACHE_STORE_MODE, getQueryOptions().getCacheStoreMode() );
}
if ( isCacheable() ) {
@ -575,25 +572,13 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
@SuppressWarnings("WeakerAccess")
protected boolean applyJpaCacheRetrieveMode(CacheRetrieveMode retrieveMode) {
final CacheMode currentCacheMode = nullif( getCacheMode(), getSession().getCacheMode() );
setCacheMode(
CacheModeHelper.interpretCacheMode(
CacheModeHelper.interpretCacheStoreMode( currentCacheMode ),
retrieveMode
)
);
getQueryOptions().setCacheRetrieveMode( retrieveMode );
return true;
}
@SuppressWarnings("WeakerAccess")
protected boolean applyJpaCacheStoreMode(CacheStoreMode storeMode) {
final CacheMode currentCacheMode = nullif( getCacheMode(), getSession().getCacheMode() );
setCacheMode(
CacheModeHelper.interpretCacheMode(
storeMode,
CacheModeHelper.interpretCacheRetrieveMode( currentCacheMode )
)
);
getQueryOptions().setCacheStoreMode( storeMode );
return true;
}

View File

@ -120,7 +120,7 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
final JdbcMutationExecutor executor = StandardJdbcMutationExecutor.INSTANCE;
final SharedSessionContractImplementor session = executionContext.getSession();
// TODO: use configurable executor instead?
// todo (6.0): use configurable executor instead?
// final SessionFactoryImplementor factory = session.getFactory();
// final JdbcServices jdbcServices = factory.getJdbcServices();
// return jdbcServices.getJdbcMutationExecutor().execute(

View File

@ -29,6 +29,7 @@ import jakarta.persistence.LockModeType;
import jakarta.persistence.Parameter;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.TemporalType;
import jakarta.persistence.Tuple;
import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.CacheMode;
@ -48,6 +49,7 @@ import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.AbstractSharedSessionContract;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.persister.entity.Loadable;
@ -187,7 +189,11 @@ public class NativeQueryImpl<R>
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
session.getFactory(),
session.isQueryParametersValidationEnabled()
);
this.querySpaces = new HashSet<>();
this.resultSetMapping = resultSetMappingCreator.get();
@ -218,21 +224,71 @@ public class NativeQueryImpl<R>
return new ResultSetMappingImpl( mappingIdentifier );
},
(resultSetMapping, querySpaceConsumer, context) -> {
if ( resultJavaType != null ) {
// todo (6.0) : really `resultJavaType` could be any type nature - basic, embedded, entity
if ( memento.getResultMappingName() != null ) {
final NamedResultSetMappingMemento resultSetMappingMemento = session.getFactory()
.getQueryEngine()
.getNamedObjectRepository()
.getResultSetMappingMemento( memento.getResultMappingName() );
if ( resultSetMappingMemento != null ) {
resultSetMappingMemento.resolve( resultSetMapping, querySpaceConsumer, context );
return true;
}
}
if ( memento.getResultMappingClass() != null ) {
resultSetMapping.addResultBuilder(
Builders.implicitEntityResultBuilder( resultJavaType, context )
Builders.implicitEntityResultBuilder(
memento.getResultMappingClass(),
context
)
);
return true;
}
if ( resultJavaType != null && resultJavaType != Tuple.class ) {
// todo (6.0): in 5.x we didn't add implicit result builders and by doing so,
// the result type check at the end of the constructor will fail like in 5.x
// final JpaMetamodel jpaMetamodel = context.getSessionFactory().getJpaMetamodel();
// if ( jpaMetamodel.findEntityType( resultJavaType ) != null ) {
// resultSetMapping.addResultBuilder(
// Builders.implicitEntityResultBuilder( resultJavaType, context )
// );
// }
// else {
// resultSetMapping.addResultBuilder(
// Builders.scalar(
// 1,
// context.getSessionFactory()
// .getTypeConfiguration()
// .getBasicTypeForJavaType( resultJavaType )
// )
// );
// }
//
// return true;
}
return false;
},
session
);
if ( resultJavaType == Tuple.class ) {
setTupleTransformer( new NativeQueryTupleTransformer() );
}
else if ( resultJavaType != null ) {
switch ( resultSetMapping.getNumberOfResultBuilders() ) {
case 0:
throw new IllegalArgumentException( "Named query exists but its result type is not compatible" );
case 1:
final Class<?> actualResultJavaType = resultSetMapping.getResultBuilders().get( 0 ).getJavaType();
if ( !resultJavaType.isAssignableFrom( actualResultJavaType ) ) {
throw buildIncompatibleException( resultJavaType, actualResultJavaType );
}
break;
default:
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
}
}
}
/**
@ -270,7 +326,11 @@ public class NativeQueryImpl<R>
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
session.getFactory(),
session.isQueryParametersValidationEnabled()
);
this.querySpaces = new HashSet<>();
this.resultSetMapping = new ResultSetMappingImpl( resultSetMappingMemento.getName() );
@ -325,12 +385,36 @@ public class NativeQueryImpl<R>
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
session.getFactory(),
session.isQueryParametersValidationEnabled()
);
this.resultSetMapping = new ResultSetMappingImpl( sqlString );
this.resultMappingSuppliedToCtor = false;
}
private IllegalArgumentException buildIncompatibleException(Class<?> resultClass, Class<?> actualResultClass) {
final String resultClassName = resultClass.getName();
final String actualResultClassName = actualResultClass.getName();
if ( resultClassName.equals( actualResultClassName ) ) {
return new IllegalArgumentException(
"Type specified for TypedQuery [" + resultClassName +
"] is incompatible with the query return type of the same name." +
" Both classes have the same name but are different as they have been loaded respectively by Classloaders " +
resultClass.getClassLoader().toString() + ", " + actualResultClass.getClassLoader().toString() +
". This suggests a classloader bug in the Runtime executing Hibernate ORM, or in the integration code."
);
}
else {
return new IllegalArgumentException(
"Type specified for TypedQuery [" + resultClassName +
"] is incompatible with query return type [" + actualResultClass + "]"
);
}
}
@Override
public String getQueryString() {
return sqlString;
@ -516,8 +600,6 @@ public class NativeQueryImpl<R>
}
private NativeSelectQueryPlan<R> createQueryPlan(ResultSetMapping resultSetMapping) {
final RowTransformer<?> rowTransformer = null;
final NativeSelectQueryDefinition queryDefinition = new NativeSelectQueryDefinition() {
@Override
public String getSqlString() {
@ -539,11 +621,6 @@ public class NativeQueryImpl<R>
return resultSetMapping;
}
@Override
public RowTransformer getRowTransformer() {
return rowTransformer;
}
@Override
public Set<String> getAffectedTableNames() {
return querySpaces;
@ -589,26 +666,6 @@ public class NativeQueryImpl<R>
return resolveSelectQueryPlan().performScroll( scrollMode, this );
}
@Override
protected void beforeQuery(boolean txnRequired) {
super.beforeQuery( txnRequired );
if ( getSynchronizedQuerySpaces() != null && !getSynchronizedQuerySpaces().isEmpty() ) {
// The application defined query spaces on the Hibernate native SQLQuery which means the query will already
// perform a partial flush according to the defined query spaces, no need to do a full flush.
return;
}
// otherwise we need to flush. the query itself is not required to execute in a transaction; if there is
// no transaction, the flush would throw a TransactionRequiredException which would potentially break existing
// apps, so we only do the flush if a transaction is in progress.
//
// NOTE : this was added for JPA initially. Perhaps we want to only do this from JPA usage?
if ( shouldFlush() ) {
getSession().flush();
}
}
protected int doExecuteUpdate() {
return resolveNonSelectQueryPlan().executeUpdate( this );
}

View File

@ -33,10 +33,8 @@ 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.ListResultsConsumer;
import org.hibernate.sql.results.spi.RowTransformer;
import org.hibernate.type.StandardBasicTypes;
/**
@ -49,23 +47,18 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
private final List<QueryParameterImplementor<?>> parameterList;
private final JdbcValuesMappingProducer resultSetMapping;
private final RowTransformer<R> rowTransformer;
public NativeSelectQueryPlanImpl(
String sql,
Set<String> affectedTableNames,
List<QueryParameterImplementor<?>> parameterList,
ResultSetMapping resultSetMapping,
RowTransformer<R> rowTransformer,
SessionFactoryImplementor sessionFactory) {
final ResultSetMappingProcessor processor = new ResultSetMappingProcessor( resultSetMapping, sessionFactory );
final SQLQueryParser parser = new SQLQueryParser( sql, processor.process(), sessionFactory );
this.sql = parser.process();
this.parameterList = parameterList;
this.resultSetMapping = processor.generateResultMapping( parser.queryHasAliases() );
this.rowTransformer = rowTransformer != null
? rowTransformer
: RowTransformerPassThruImpl.instance();
if ( affectedTableNames == null ) {
affectedTableNames = new HashSet<>();
}
@ -126,16 +119,16 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE;
// TODO: use configurable executor instead?
// todo (6.0): use configurable executor instead?
// final SharedSessionContractImplementor session = executionContext.getSession();
// final SessionFactoryImplementor factory = session.getFactory();
// final JdbcServices jdbcServices = factory.getJdbcServices();
// return jdbcServices.getJdbcMutationExecutor().execute(
// return jdbcServices.getJdbcSelectExecutor().execute(
return executor.list(
jdbcSelect,
jdbcParameterBindings,
executionContext,
rowTransformer,
null,
ListResultsConsumer.UniqueSemantic.NONE
);
}
@ -149,7 +142,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
final JdbcParameterBindings jdbcParameterBindings;
final QueryParameterBindings queryParameterBindings = executionContext.getQueryParameterBindings();
if ( parameterList.isEmpty() ) {
if ( parameterList == null || parameterList.isEmpty() ) {
jdbcParameterBinders = Collections.emptyList();
jdbcParameterBindings = JdbcParameterBindings.NO_BINDINGS;
}
@ -190,12 +183,17 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE;
// todo (6.0): use configurable executor instead?
// final SharedSessionContractImplementor session = executionContext.getSession();
// final SessionFactoryImplementor factory = session.getFactory();
// final JdbcServices jdbcServices = factory.getJdbcServices();
// return jdbcServices.getJdbcSelectExecutor().scroll(
return executor.scroll(
jdbcSelect,
scrollMode,
jdbcParameterBindings,
executionContext,
rowTransformer
null
);
}
}

View File

@ -32,9 +32,6 @@ public interface NativeSelectQueryDefinition<R> {
Set<String> getAffectedTableNames();
RowTransformer<R> getRowTransformer();
// todo (6.0) : drop support for executing callables via NativeQuery
boolean isCallable();

View File

@ -143,7 +143,11 @@ public class QuerySqmImpl<R>
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
producer.getFactory(),
producer.isQueryParametersValidationEnabled()
);
applyOptions( memento );
}
@ -186,7 +190,7 @@ public class QuerySqmImpl<R>
this.sqmStatement = hqlInterpretation.getSqmStatement();
if ( resultType != null ) {
SqmUtil.verifyIsSelectStatement( sqmStatement );
SqmUtil.verifyIsSelectStatement( sqmStatement, hqlString );
visitQueryReturnType(
( (SqmSelectStatement<R>) sqmStatement ).getQueryPart(),
resultType,
@ -200,7 +204,11 @@ public class QuerySqmImpl<R>
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
producer.getFactory(),
producer.isQueryParametersValidationEnabled()
);
}
/**
@ -213,7 +221,7 @@ public class QuerySqmImpl<R>
super( producer );
if ( resultType != null ) {
SqmUtil.verifyIsSelectStatement( sqmStatement );
SqmUtil.verifyIsSelectStatement( sqmStatement, null );
final SqmQueryPart<R> queryPart = ( (SqmSelectStatement<R>) sqmStatement ).getQueryPart();
// For criteria queries, we have to validate the fetch structure here
queryPart.validateQueryGroupFetchStructure();
@ -243,7 +251,11 @@ public class QuerySqmImpl<R>
this.parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
}
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
producer.getFactory(),
producer.isQueryParametersValidationEnabled()
);
// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : this.domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
@ -575,7 +587,7 @@ public class QuerySqmImpl<R>
@Override
protected List<R> doList() {
SqmUtil.verifyIsSelectStatement( getSqmStatement() );
SqmUtil.verifyIsSelectStatement( getSqmStatement(), hqlString );
final SqmSelectStatement<?> selectStatement = (SqmSelectStatement<?>) getSqmStatement();
getSession().prepareForQueryExecution( requiresTxn( getLockOptions().findGreatestLockMode() ) );
@ -710,7 +722,7 @@ public class QuerySqmImpl<R>
@Override
public ScrollableResultsImplementor<R> scroll(ScrollMode scrollMode) {
SqmUtil.verifyIsSelectStatement( getSqmStatement() );
SqmUtil.verifyIsSelectStatement( getSqmStatement(), hqlString );
getSession().prepareForQueryExecution( requiresTxn( getLockOptions().findGreatestLockMode() ) );
return resolveSelectQueryPlan().performScroll( scrollMode, this );
@ -718,7 +730,7 @@ public class QuerySqmImpl<R>
@Override
protected int doExecuteUpdate() {
SqmUtil.verifyIsNonSelectStatement( getSqmStatement() );
SqmUtil.verifyIsNonSelectStatement( getSqmStatement(), hqlString );
getSession().prepareForQueryExecution( true );
return resolveNonSelectQueryPlan().executeUpdate( this );

View File

@ -70,7 +70,7 @@ public class SqmUtil {
private SqmUtil() {
}
public static void verifyIsSelectStatement(SqmStatement sqm) {
public static void verifyIsSelectStatement(SqmStatement sqm, String hqlString) {
if ( !(sqm instanceof SqmSelectStatement) ) {
throw new IllegalQueryOperationException(
String.format(
@ -78,12 +78,14 @@ public class SqmUtil {
"Expecting a SELECT Query [%s], but found %s",
SqmSelectStatement.class.getName(),
sqm.getClass().getName()
)
),
hqlString,
null
);
}
}
public static void verifyIsNonSelectStatement(SqmStatement sqm) {
public static void verifyIsNonSelectStatement(SqmStatement sqm, String hqlString) {
if ( !(sqm instanceof SqmDmlStatement) ) {
throw new IllegalQueryOperationException(
String.format(
@ -91,7 +93,9 @@ public class SqmUtil {
"Expecting a non-SELECT Query [%s], but found %s",
SqmDmlStatement.class.getName(),
sqm.getClass().getName()
)
),
hqlString,
null
);
}
}

View File

@ -73,6 +73,7 @@ import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
@ -2710,7 +2711,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
final MappingModelExpressable keyExpressable = getKeyExpressable( mappingModelExpressable );
if ( keyExpressable == null ) {
throw new IllegalArgumentException( "Could not determine type for null literal" );
// todo (6.0): this should be fine, right?
return new NullnessLiteral( JavaObjectType.INSTANCE );
// throw new IllegalArgumentException( "Could not determine type for null literal" );
}
final List<Expression> expressions = new ArrayList<>( keyExpressable.getJdbcTypeCount() );
@ -2775,6 +2778,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
else if ( literalValue instanceof String ) {
discriminatorValue = javaTypeDescriptor.fromString( (String) literalValue );
}
else if ( creationContext.getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
discriminatorValue = literalValue;
}
else {
discriminatorValue = javaTypeDescriptor.coerce( literalValue, null );
}
@ -3171,7 +3177,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
assert parameterSqmType != null;
if ( parameterSqmType == null || parameterSqmType == StandardBasicTypes.OBJECT_TYPE ) {
assert binding.getBindValue() == null;
// todo (6.0): this should be fine, right?
return StandardBasicTypes.OBJECT_TYPE;
}
if ( parameterSqmType instanceof SqmPath ) {
final SqmPath sqmPath = (SqmPath) parameterSqmType;
@ -3191,16 +3201,25 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return (BasicValuedMapping) parameterSqmType;
}
if ( parameterSqmType instanceof SqmPathSource<?> ) {
if ( parameterSqmType instanceof CompositeSqmPathSource ) {
// Try to infer the value mapping since the other side apparently is a path source
final MappingModelExpressable<?> inferredValueMapping = getInferredValueMapping();
if ( inferredValueMapping != null ) {
return inferredValueMapping;
}
throw new NotYetImplementedFor6Exception( "Support for embedded-valued parameters not yet implemented" );
}
if ( parameterSqmType instanceof CompositeSqmPathSource ) {
throw new NotYetImplementedFor6Exception( "Support for embedded-valued parameters not yet implemented" );
if ( parameterSqmType instanceof SqmPathSource<?> || parameterSqmType instanceof BasicDomainType<?> ) {
// Try to infer the value mapping since the other side apparently is a path source
final MappingModelExpressable<?> inferredValueMapping = getInferredValueMapping();
if ( inferredValueMapping != null ) {
return inferredValueMapping;
}
return getTypeConfiguration().getBasicTypeForJavaType(
( (SqmExpressable<?>) parameterSqmType ).getExpressableJavaTypeDescriptor()
.getJavaTypeClass()
);
}
throw new ConversionException( "Could not determine ValueMapping for SqmParameter: " + sqmParameter );

View File

@ -19,8 +19,6 @@ public abstract class AbstractSqmSpecificPluralPartPath<T> extends AbstractSqmPa
private final SqmPath<?> pluralDomainPath;
private final PluralPersistentAttribute<?, ?, T> pluralAttribute;
private String alias;
@SuppressWarnings("WeakerAccess")
public AbstractSqmSpecificPluralPartPath(
NavigablePath navigablePath,
@ -51,16 +49,6 @@ public abstract class AbstractSqmSpecificPluralPartPath<T> extends AbstractSqmPa
return pluralDomainPath;
}
@Override
public String getExplicitAlias() {
return alias;
}
@Override
public void setExplicitAlias(String explicitAlias) {
this.alias = explicitAlias;
}
@Override
public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException {
if ( getReferencedPathSource().getSqmPathType() instanceof EntityDomainType ) {

View File

@ -409,7 +409,7 @@ public class SqmPolymorphicRootDescriptor<T> implements EntityDomainType<T> {
}
@Override
public SqmPathSource getIdentifierDescriptor() {
public SqmPathSource<?> getIdentifierDescriptor() {
return null;
}

View File

@ -34,7 +34,7 @@ public abstract class AbstractSqmExpression<T> extends AbstractJpaSelection<T> i
}
@Override
public final void applyInferableType(SqmExpressable<?> type) {
public void applyInferableType(SqmExpressable<?> type) {
// if ( type == null ) {
// return;
// }

View File

@ -7,7 +7,10 @@
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
/**
* Common support for SqmParameter impls
@ -25,6 +28,22 @@ public abstract class AbstractSqmParameter<T> extends AbstractSqmExpression<T> i
this.canBeMultiValued = canBeMultiValued;
}
@Override
public void applyInferableType(SqmExpressable<?> type) {
if ( type == null ) {
return;
}
else if ( type instanceof PluralPersistentAttribute<?, ?, ?> ) {
type = ( (PluralPersistentAttribute<?, ?, ?>) type ).getElementType();
}
final SqmExpressable<?> oldType = getNodeType();
final SqmExpressable<?> newType = QueryHelper.highestPrecedenceType( oldType, type );
if ( newType != null && newType != oldType ) {
internalApplyInferableType( newType );
}
}
@Override
public String getName() {
return null;

View File

@ -17,6 +17,7 @@ public class JdbcParameterBindingImpl implements JdbcParameterBinding {
private final Object bindValue;
public JdbcParameterBindingImpl(JdbcMapping jdbcMapping, Object bindValue) {
assert bindValue == null || jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass().isInstance( bindValue );
this.jdbcMapping = jdbcMapping;
this.bindValue = bindValue;
}

View File

@ -23,6 +23,7 @@ import org.hibernate.cache.spi.QueryResultsCache;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.TupleTransformer;
import org.hibernate.query.internal.ScrollableResultsIterator;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.sql.exec.SqlExecLogger;
@ -30,8 +31,11 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
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.graph.DomainResult;
import org.hibernate.sql.results.internal.ResultsHelper;
import org.hibernate.sql.results.internal.RowProcessingStateStandardImpl;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
import org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess;
import org.hibernate.sql.results.jdbc.internal.JdbcValuesCacheHit;
import org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl;
@ -181,6 +185,21 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
deferredResultSetAccess
);
if ( rowTransformer == null ) {
final TupleTransformer<R> tupleTransformer = executionContext.getQueryOptions().getTupleTransformer();
if ( tupleTransformer == null ) {
rowTransformer = RowTransformerPassThruImpl.instance();
}
else {
final List<DomainResult<?>> domainResults = jdbcValues.getValuesMapping().getDomainResults();
final String[] aliases = new String[domainResults.size()];
for ( int i = 0; i < domainResults.size(); i++ ) {
aliases[i] = domainResults.get( i ).getResultVariable();
}
rowTransformer = new RowTransformerTupleTransformerAdapter<>( aliases, tupleTransformer );
}
}
final boolean stats;
long startTime = 0;
final StatisticsImplementor statistics = executionContext.getSession().getFactory().getStatistics();

View File

@ -11,8 +11,10 @@ import java.sql.SQLException;
import java.util.function.BiConsumer;
import java.util.function.Function;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcMutation;
@ -44,11 +46,23 @@ public class StandardJdbcMutationExecutor implements JdbcMutationExecutor {
.getLogicalConnection();
final JdbcServices jdbcServices = session.getJdbcServices();
final String sql = jdbcMutation.getSql();
final QueryOptions queryOptions = executionContext.getQueryOptions();
final String finalSql;
if ( queryOptions == null ) {
finalSql = jdbcMutation.getSql();
}
else {
final Dialect dialect = jdbcServices.getDialect();
final String sql = jdbcMutation.getSql();
finalSql = dialect.addSqlHintOrComment(
sql,
queryOptions,
executionContext.getSession().getFactory().getSessionFactoryOptions().isCommentsEnabled()
);
}
try {
// prepare the query
final PreparedStatement preparedStatement = statementCreator.apply( sql );
final PreparedStatement preparedStatement = statementCreator.apply( finalSql );
try {
if ( executionContext.getQueryOptions().getTimeout() != null ) {
@ -84,7 +98,7 @@ public class StandardJdbcMutationExecutor implements JdbcMutationExecutor {
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert(
e,
"JDBC exception executing SQL [" + sql + "]"
"JDBC exception executing SQL [" + finalSql + "]"
);
}
finally {

View File

@ -13,6 +13,7 @@ import java.util.function.BiConsumer;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.Bindable;
import org.hibernate.query.internal.BindingTypeHelper;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
@ -23,7 +24,7 @@ import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
* @apiNote "Externalized" because some JDBC parameter values are
* intrinsically part of the parameter itself and we do not need to
* locate a JdbcParameterBinding. E.g., consider a
* {@link org.hibernate.sql.ast.tree.expression.LiteralParameter}
* {@link org.hibernate.sql.ast.tree.expression.LiteralAsParameter}
* which actually encapsulates the actually literal value inside
* itself - to create the binder and actually perform the binding
* is only dependent on the LiteralParameter
@ -79,11 +80,12 @@ public interface JdbcParameterBindings {
value,
clause,
offset,
(selectionIndex, jdbcValue, type) ->
addBinding(
jdbcParameters.get( selectionIndex ),
new JdbcParameterBindingImpl( type, jdbcValue )
)
(selectionIndex, jdbcValue, type) -> {
addBinding(
jdbcParameters.get( selectionIndex ),
new JdbcParameterBindingImpl( BindingTypeHelper.INSTANCE.resolveBindType( jdbcValue, type ), jdbcValue )
);
}
,
session
);

View File

@ -9,6 +9,9 @@ package org.hibernate.sql.results.jdbc.internal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import javax.persistence.EnumType;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -16,6 +19,7 @@ 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.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -69,28 +73,60 @@ public interface ResultSetAccess extends JdbcValuesMetadata {
@Override
default <J> BasicType<J> resolveType(int position, JavaTypeDescriptor<J> explicitJavaTypeDescriptor) {
final TypeConfiguration typeConfiguration = getFactory().getTypeConfiguration();
final JdbcServices jdbcServices = getFactory().getJdbcServices();
try {
final TypeConfiguration typeConfiguration = getFactory().getTypeConfiguration();
final ResultSetMetaData metaData = getResultSet().getMetaData();
final JdbcTypeDescriptor jdbcTypeDescriptor = jdbcServices.getDialect()
final int columnType = metaData.getColumnType( position );
final int scale = metaData.getScale( position );
final int precision = metaData.getPrecision( position );
final int length;
if ( columnType == Types.CHAR && precision == 0 ) {
length = metaData.getColumnDisplaySize( position );
}
else {
length = precision;
}
final JdbcTypeDescriptor resolvedJdbcTypeDescriptor = jdbcServices.getDialect()
.resolveSqlTypeDescriptor(
metaData.getColumnType( position ),
metaData.getPrecision( position ),
metaData.getScale( position ),
columnType,
length,
scale,
typeConfiguration.getJdbcTypeDescriptorRegistry()
);
final JavaTypeDescriptor<J> javaTypeDescriptor;
if ( explicitJavaTypeDescriptor == null ) {
javaTypeDescriptor = jdbcTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
final JdbcTypeDescriptor jdbcTypeDescriptor;
// If there is an explicit JavaTypeDescriptor, then prefer its recommended JDBC type
if ( explicitJavaTypeDescriptor != null ) {
javaTypeDescriptor = explicitJavaTypeDescriptor;
jdbcTypeDescriptor = explicitJavaTypeDescriptor.getRecommendedJdbcType(
new JdbcTypeDescriptorIndicators() {
@Override
public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;
}
@Override
public long getColumnLength() {
return length;
}
@Override
public EnumType getEnumeratedType() {
return resolvedJdbcTypeDescriptor.isNumber() ? EnumType.ORDINAL : EnumType.STRING;
}
}
);
}
else {
javaTypeDescriptor = explicitJavaTypeDescriptor;
jdbcTypeDescriptor = resolvedJdbcTypeDescriptor;
javaTypeDescriptor = jdbcTypeDescriptor.getJdbcRecommendedJavaTypeMapping(
length,
scale,
typeConfiguration
);
}
return typeConfiguration.getBasicTypeRegistry().resolve(
javaTypeDescriptor,
jdbcTypeDescriptor
);
return typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, jdbcTypeDescriptor );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert(

View File

@ -197,7 +197,11 @@ public class EnumType<T extends Enum<T>>
private BasicJavaDescriptor<?> resolveRelationalJavaTypeDescriptor(
LocalJdbcTypeDescriptorIndicators indicators,
EnumJavaTypeDescriptor<?> enumJavaDescriptor) {
return enumJavaDescriptor.getRecommendedJdbcType( indicators ).getJdbcRecommendedJavaTypeMapping( typeConfiguration );
return enumJavaDescriptor.getRecommendedJdbcType( indicators ).getJdbcRecommendedJavaTypeMapping(
null,
null,
typeConfiguration
);
}
private jakarta.persistence.EnumType getEnumType(ParameterType reader) {

View File

@ -76,7 +76,10 @@ public class PostgresUUIDType extends AbstractSingleColumnStandardBasicType<UUID
}
@Override
public <J> BasicJavaDescriptor<J> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <J> BasicJavaDescriptor<J> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<J>) typeConfiguration.getJavaTypeDescriptorRegistry().resolveDescriptor( UUID.class );
}

View File

@ -42,7 +42,10 @@ public class BigIntTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Long.class );
}

View File

@ -53,7 +53,10 @@ public abstract class BlobTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Blob.class );
}

View File

@ -51,7 +51,10 @@ public class BooleanTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Boolean.class );
}

View File

@ -56,7 +56,10 @@ public class DateTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Date.class );
}

View File

@ -53,7 +53,10 @@ public class DecimalTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( BigDecimal.class );
}

View File

@ -63,7 +63,10 @@ public class DoubleTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Double.class );
}

View File

@ -52,7 +52,10 @@ public class FloatTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Double.class );
}

View File

@ -52,7 +52,10 @@ public class IntegerTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Integer.class );
}

View File

@ -65,7 +65,10 @@ public interface JdbcTypeDescriptor extends Serializable {
*/
boolean canBeRemapped();
default <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
default <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer precision,
Integer scale,
TypeConfiguration typeConfiguration) {
// match legacy behavior
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor(
JdbcTypeJavaClassMappings.INSTANCE.determineJavaClassForJdbcTypeCode( getJdbcTypeCode() )

View File

@ -52,7 +52,10 @@ public class NVarcharTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
}

View File

@ -41,7 +41,10 @@ public class RealTypeDescriptor extends FloatTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Float.class );
}
}

View File

@ -52,7 +52,10 @@ public class SmallIntTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Short.class );
}

View File

@ -56,7 +56,10 @@ public class TimeTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Time.class );
}

View File

@ -56,7 +56,10 @@ public class TimestampTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Timestamp.class );
}

View File

@ -55,7 +55,10 @@ public class TimestampWithTimeZoneDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( OffsetDateTime.class );
}

View File

@ -55,7 +55,10 @@ public class TinyIntTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Byte.class );
}

View File

@ -59,7 +59,10 @@ public class VarbinaryTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( byte[].class );
}

View File

@ -52,7 +52,13 @@ public class VarcharTypeDescriptor implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
if ( length != null && length == 1 ) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Character.class );
}
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
}

View File

@ -71,7 +71,10 @@ public class UserTypeSqlTypeAdapter<J> implements JdbcTypeDescriptor {
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
//noinspection unchecked
return (BasicJavaDescriptor<T>) jtd;
}

View File

@ -26,7 +26,7 @@ import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.SkipForDialect;
@ -35,7 +35,7 @@ import org.junit.Test;
/**
* @author Steve Ebersole
*/
@SkipForDialect(value = Oracle8iDialect.class, jiraKey = "HHH-10323")
@SkipForDialect(value = OracleDialect.class, jiraKey = "HHH-10323")
public class ConstructorResultNativeQueryTest extends BaseEntityManagerFunctionalTestCase {
@Entity( name = "Person" )
@SqlResultSetMappings(

View File

@ -86,7 +86,7 @@ public class NamedQueryCommentTest extends BaseEntityManagerFunctionalTestCase {
sqlStatementInterceptor.assertExecutedCount(1);
sqlStatementInterceptor.assertExecuted(
"/* COMMENT_SELECT_INDEX_game_title */ select namedquery0_.id as id1_0_, namedquery0_.title as title2_0_ from game namedquery0_ where namedquery0_.title=?"
"/* COMMENT_SELECT_INDEX_game_title */ select g1_0.id,g1_0.title from game g1_0 where g1_0.title=?"
);
} );
}
@ -206,8 +206,8 @@ public class NamedQueryCommentTest extends BaseEntityManagerFunctionalTestCase {
sqlStatementInterceptor.assertExecutedCount(1);
sqlStatementInterceptor.assertExecuted(
"/* COMMENT_SELECT_INDEX_game_title */ select namedquery0_.id as id1_0_, namedquery0_.title as title2_0_ from game namedquery0_ use index (idx_game_id) where namedquery0_.title=?" )
;
"/* COMMENT_SELECT_INDEX_game_title */ select g1_0.id,g1_0.title from game g1_0 use index (idx_game_id) where g1_0.title=?"
);
} );
}

View File

@ -182,7 +182,7 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
@Test
@TestForIssue(jiraKey = "HHH-11413")
public void testNamedNativeQueryExceptionNoRedultDefined() {
public void testNamedNativeQueryExceptionNoResultDefined() {
doInJPA( this::entityManagerFactory, entityManager -> {
assertThrows(
"Named query exists but its result type is not compatible",

View File

@ -8,11 +8,7 @@ package org.hibernate.orm.test.jpa.query;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
@ -31,6 +27,7 @@ import jakarta.persistence.MappedSuperclass;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.Nationalized;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@ -38,27 +35,18 @@ import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.testing.orm.jpa.PersistenceUnitDescriptorAdapter;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.BigDecimalTypeDescriptor;
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
import org.hibernate.type.descriptor.java.FloatTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.BasicBinder;
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
import org.hibernate.type.descriptor.jdbc.BinaryTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.CharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.NumericTypeDescriptor;
import org.hibernate.testing.RequiresDialect;
@ -67,9 +55,6 @@ import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.CustomRunner;
import org.hibernate.testing.orm.junit.DialectContext;
import org.hibernate.testing.transaction.TransactionUtil;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
import org.hibernate.type.spi.TypeConfiguration;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
@ -131,7 +116,7 @@ public class NativeQueryResultTypeAutoDiscoveryTest {
@Test
// Postgresql turns tinyints into shorts in resultsets, and advertises the type as short in the metadata.
// Not much we can do about that.
@SkipForDialect(PostgreSQL81Dialect.class)
@SkipForDialect(PostgreSQLDialect.class)
public void tinyintType() {
createEntityManagerFactory( TinyintEntity.class );
doTest( TinyintEntity.class, (byte)127 );
@ -526,31 +511,13 @@ public class NativeQueryResultTypeAutoDiscoveryTest {
}
@Entity(name = "bitEntity")
@TypeDef(name = BooleanAsBitType.NAME, typeClass = BooleanAsBitType.class)
public static class BitEntity extends TestedEntity<Boolean> {
/**
* The custom type sets the SQL type to {@link Types#BIT}
* instead of the default {@link Types#BOOLEAN}.
*/
@Type(type = BooleanAsBitType.NAME)
@JdbcTypeCode(Types.BIT)
public Boolean getTestedProperty() {
return testedProperty;
}
}
public static class BooleanAsBitType extends AbstractSingleColumnStandardBasicType<Boolean> {
public static final String NAME = "boolean_as_bit";
public BooleanAsBitType() {
super( BitTypeDescriptor.INSTANCE, BooleanTypeDescriptor.INSTANCE );
}
@Override
public String getName() {
return NAME;
}
}
public static class FloatAsRealType extends AbstractSingleColumnStandardBasicType<Float> {
public static final String NAME = "float_as_real";
@ -610,87 +577,3 @@ public class NativeQueryResultTypeAutoDiscoveryTest {
}
class BitTypeDescriptor implements JdbcTypeDescriptor {
public static final BitTypeDescriptor INSTANCE = new BitTypeDescriptor();
public BitTypeDescriptor() {
}
public int getJdbcTypeCode() {
return Types.BIT;
}
@Override
public String getFriendlyName() {
return "BIT";
}
@Override
public String toString() {
return "BitTypeDescriptor";
}
@Override
public boolean canBeRemapped() {
return true;
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Boolean.class );
}
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
if ( javaTypeDescriptor.getJavaType().equals(Boolean.class) ) {
//this is to allow literals to be formatted correctly when
//we are in the legacy Boolean-to-BIT JDBC type mapping mode
return new BasicJdbcLiteralFormatter( javaTypeDescriptor ) {
@Override
public String toJdbcLiteral(Object value, Dialect dialect, WrapperOptions wrapperOptions) {
Boolean bool = unwrap( value, Boolean.class, wrapperOptions );
return bool ? "1" : "0";
}
};
}
else {
return (value, dialect, wrapperOptions) -> value.toString();
}
}
@Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
st.setBoolean( index, javaTypeDescriptor.unwrap( value, Boolean.class, options ) );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setBoolean( name, javaTypeDescriptor.unwrap( value, Boolean.class, options ) );
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBoolean( paramIndex ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBoolean( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBoolean( name ), options );
}
};
}
}

View File

@ -11,6 +11,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Map;
import java.util.Objects;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
@ -22,6 +23,7 @@ import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.Type;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.usertype.UserType;
@ -39,6 +41,11 @@ public class QueryParametersValidationTest extends BaseEntityManagerFunctionalTe
return new Class[] {TestEntity.class};
}
@Override
protected void addConfigOptions(Map options) {
options.put( AvailableSettings.JPA_LOAD_BY_ID_COMPLIANCE, "true" );
}
@TestForIssue(jiraKey = "HHH-11397")
@Test(expected = IllegalArgumentException.class)
public void setParameterWithWrongTypeShouldThrowIllegalArgumentException() {

View File

@ -27,8 +27,8 @@ import org.hibernate.QueryException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.PostgreSQL9Dialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.PostgresPlusDialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
@ -382,8 +382,8 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
}
@Test
@SkipForDialect(value = Oracle8iDialect.class, jiraKey = "HHH-10161", comment = "Cannot convert untyped null (assumed to be BINARY type) to NUMBER")
@SkipForDialect(value = PostgreSQL9Dialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = OracleDialect.class, jiraKey = "HHH-10161", comment = "Cannot convert untyped null (assumed to be BINARY type) to NUMBER")
@SkipForDialect(value = PostgreSQLDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = PostgresPlusDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = CockroachDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = DerbyDialect.class, comment = "Cannot convert untyped null (assumed to be VARBINARY type) to INTEGER")
@ -419,10 +419,10 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
@Test
@TestForIssue(jiraKey = "HHH-10161")
@SkipForDialect(value = PostgreSQL9Dialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = PostgreSQLDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = PostgresPlusDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = CockroachDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = Oracle8iDialect.class, comment = "ORA-00932: inconsistent datatypes: expected NUMBER got BINARY")
@SkipForDialect(value = OracleDialect.class, comment = "ORA-00932: inconsistent datatypes: expected NUMBER got BINARY")
@SkipForDialect(value = DerbyDialect.class, comment = "Cannot convert untyped null (assumed to be VARBINARY type) to INTEGER")
public void testNativeQueryNullPositionalParameterParameter() throws Exception {
EntityManager em = getOrCreateEntityManager();
@ -472,8 +472,8 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
}
@Test
@SkipForDialect(value = Oracle8iDialect.class, jiraKey = "HHH-10161", comment = "Cannot convert untyped null (assumed to be BINARY type) to NUMBER")
@SkipForDialect(value = PostgreSQL9Dialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = OracleDialect.class, jiraKey = "HHH-10161", comment = "Cannot convert untyped null (assumed to be BINARY type) to NUMBER")
@SkipForDialect(value = PostgreSQLDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = PostgresPlusDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = CockroachDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = DerbyDialect.class, comment = "Cannot convert untyped null (assumed to be VARBINARY type) to INTEGER")
@ -509,10 +509,10 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
@Test
@TestForIssue(jiraKey = "HHH-10161")
@SkipForDialect(value = PostgreSQL9Dialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = PostgreSQLDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = PostgresPlusDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = CockroachDialect.class, jiraKey = "HHH-10312", comment = "Cannot convert untyped null (assumed to be bytea type) to bigint")
@SkipForDialect(value = Oracle8iDialect.class, comment = "ORA-00932: inconsistent datatypes: expected NUMBER got BINARY")
@SkipForDialect(value = OracleDialect.class, comment = "ORA-00932: inconsistent datatypes: expected NUMBER got BINARY")
@SkipForDialect(value = DerbyDialect.class, comment = "Cannot convert untyped null (assumed to be VARBINARY type) to INTEGER")
public void testNativeQueryNullNamedParameterParameter() throws Exception {
EntityManager em = getOrCreateEntityManager();