From f48f486ec63eecaf7956bab37bb4975836abae24 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 11 Jul 2019 10:53:54 +0100 Subject: [PATCH] 6 - SQM based on JPA type system --- .../ResultsetMappingSecondPass.java | 280 +++++++++--------- .../query/spi/OrdinalParameterDescriptor.java | 6 + .../model/domain/AllowableParameterType.java | 4 +- .../AbstractCollectionPersister.java | 11 + .../collection/CollectionPersister.java | 12 + .../procedure/internal/ProcedureCallImpl.java | 90 +++--- .../internal/ProcedureParameterImpl.java | 226 +++++++------- .../internal/QueryParameterBindingImpl.java | 2 +- .../sql/spi/ResultSetMappingDescriptor.java | 2 +- .../sql/results/spi/LoadContexts.java | 2 +- .../GoofyPersisterClassProvider.java | 21 ++ 11 files changed, 355 insertions(+), 301 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java index fe366f8497..68bc5e84f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java @@ -22,6 +22,7 @@ import javax.persistence.SqlResultSetMapping; import org.hibernate.LockMode; import org.hibernate.MappingException; +import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.QuerySecondPass; @@ -57,145 +58,146 @@ public class ResultsetMappingSecondPass implements QuerySecondPass { @Override public void doSecondPass(Map persistentClasses) throws MappingException { //TODO add parameters checkings - if ( ann == null ) return; - ResultSetMappingDescriptor definition = new ResultSetMappingDescriptor( ann.name() ); - LOG.debugf( "Binding result set mapping: %s", definition.getName() ); - - int entityAliasIndex = 0; - - for (EntityResult entity : ann.entities()) { - //TODO parameterize lock mode? - List properties = new ArrayList(); - List propertyNames = new ArrayList(); - for (FieldResult field : entity.fields()) { - //use an ArrayList cause we might have several columns per root property - String name = field.name(); - if ( name.indexOf( '.' ) == -1 ) { - //regular property - properties.add( field ); - propertyNames.add( name ); - } - else { - /** - * Reorder properties - * 1. get the parent property - * 2. list all the properties following the expected one in the parent property - * 3. calculate the lowest index and insert the property - */ - PersistentClass pc = context.getMetadataCollector().getEntityBinding( - entity.entityClass().getName() - ); - if ( pc == null ) { - throw new MappingException( - String.format( - Locale.ENGLISH, - "Could not resolve entity [%s] referenced in SqlResultSetMapping [%s]", - entity.entityClass().getName(), - ann.name() - ) - ); - } - int dotIndex = name.lastIndexOf( '.' ); - String reducedName = name.substring( 0, dotIndex ); - Iterator parentPropItr = getSubPropertyIterator( pc, reducedName ); - List followers = getFollowers( parentPropItr, reducedName, name ); - - int index = propertyNames.size(); - for ( String follower : followers ) { - int currentIndex = getIndexOfFirstMatchingProperty( propertyNames, follower ); - index = currentIndex != -1 && currentIndex < index ? currentIndex : index; - } - propertyNames.add( index, name ); - properties.add( index, field ); - } - } - - Set uniqueReturnProperty = new HashSet(); - Map> propertyResultsTmp = new HashMap>(); - for ( Object property : properties ) { - final FieldResult propertyresult = ( FieldResult ) property; - final String name = propertyresult.name(); - if ( "class".equals( name ) ) { - throw new MappingException( - "class is not a valid property name to use in a @FieldResult, use @Entity(discriminatorColumn) instead" - ); - } - - if ( uniqueReturnProperty.contains( name ) ) { - throw new MappingException( - "duplicate @FieldResult for property " + name + - " on @Entity " + entity.entityClass().getName() + " in " + ann.name() - ); - } - uniqueReturnProperty.add( name ); - - final String quotingNormalizedColumnName = normalizeColumnQuoting( propertyresult.column() ); - - String key = StringHelper.root( name ); - ArrayList intermediateResults = propertyResultsTmp.get( key ); - if ( intermediateResults == null ) { - intermediateResults = new ArrayList(); - propertyResultsTmp.put( key, intermediateResults ); - } - intermediateResults.add( quotingNormalizedColumnName ); - } - - Map propertyResults = new HashMap(); - for ( Map.Entry> entry : propertyResultsTmp.entrySet() ) { - propertyResults.put( - entry.getKey(), - entry.getValue().toArray( new String[ entry.getValue().size() ] ) - ); - } - - if ( !BinderHelper.isEmptyAnnotationValue( entity.discriminatorColumn() ) ) { - final String quotingNormalizedName = normalizeColumnQuoting( entity.discriminatorColumn() ); - propertyResults.put( "class", new String[] { quotingNormalizedName } ); - } - - if ( propertyResults.isEmpty() ) { - propertyResults = java.util.Collections.emptyMap(); - } - - NativeSQLQueryRootReturn result = new NativeSQLQueryRootReturn( - "alias" + entityAliasIndex++, - entity.entityClass().getName(), - propertyResults, - LockMode.READ - ); - definition.addQueryReturn( result ); - } - - for ( ColumnResult column : ann.columns() ) { - definition.addQueryReturn( - new NativeSQLQueryScalarReturn( - normalizeColumnQuoting( column.name() ), - column.type() != null ? context.getMetadataCollector().getTypeResolver().heuristicType( column.type().getName() ) : null - ) - ); - } - - for ( ConstructorResult constructorResult : ann.classes() ) { - List columnReturns = new ArrayList(); - for ( ColumnResult columnResult : constructorResult.columns() ) { - columnReturns.add( - new NativeSQLQueryScalarReturn( - normalizeColumnQuoting( columnResult.name() ), - columnResult.type() != null ? context.getMetadataCollector().getTypeResolver().heuristicType( columnResult.type().getName() ) : null - ) - ); - } - definition.addQueryReturn( - new NativeSQLQueryConstructorReturn( constructorResult.targetClass(), columnReturns ) - ); - } - - if ( isDefault ) { - context.getMetadataCollector().addDefaultResultSetMapping( definition ); - } - else { - context.getMetadataCollector().addResultSetMapping( definition ); - } +// if ( ann == null ) return; +// ResultSetMappingDescriptor definition = new ResultSetMappingDescriptor( ann.name() ); +// LOG.debugf( "Binding result set mapping: %s", definition.getName() ); +// +// int entityAliasIndex = 0; +// +// for (EntityResult entity : ann.entities()) { +// //TODO parameterize lock mode? +// List properties = new ArrayList(); +// List propertyNames = new ArrayList(); +// for (FieldResult field : entity.fields()) { +// //use an ArrayList cause we might have several columns per root property +// String name = field.name(); +// if ( name.indexOf( '.' ) == -1 ) { +// //regular property +// properties.add( field ); +// propertyNames.add( name ); +// } +// else { +// /** +// * Reorder properties +// * 1. get the parent property +// * 2. list all the properties following the expected one in the parent property +// * 3. calculate the lowest index and insert the property +// */ +// PersistentClass pc = context.getMetadataCollector().getEntityBinding( +// entity.entityClass().getName() +// ); +// if ( pc == null ) { +// throw new MappingException( +// String.format( +// Locale.ENGLISH, +// "Could not resolve entity [%s] referenced in SqlResultSetMapping [%s]", +// entity.entityClass().getName(), +// ann.name() +// ) +// ); +// } +// int dotIndex = name.lastIndexOf( '.' ); +// String reducedName = name.substring( 0, dotIndex ); +// Iterator parentPropItr = getSubPropertyIterator( pc, reducedName ); +// List followers = getFollowers( parentPropItr, reducedName, name ); +// +// int index = propertyNames.size(); +// for ( String follower : followers ) { +// int currentIndex = getIndexOfFirstMatchingProperty( propertyNames, follower ); +// index = currentIndex != -1 && currentIndex < index ? currentIndex : index; +// } +// propertyNames.add( index, name ); +// properties.add( index, field ); +// } +// } +// +// Set uniqueReturnProperty = new HashSet(); +// Map> propertyResultsTmp = new HashMap>(); +// for ( Object property : properties ) { +// final FieldResult propertyresult = ( FieldResult ) property; +// final String name = propertyresult.name(); +// if ( "class".equals( name ) ) { +// throw new MappingException( +// "class is not a valid property name to use in a @FieldResult, use @Entity(discriminatorColumn) instead" +// ); +// } +// +// if ( uniqueReturnProperty.contains( name ) ) { +// throw new MappingException( +// "duplicate @FieldResult for property " + name + +// " on @Entity " + entity.entityClass().getName() + " in " + ann.name() +// ); +// } +// uniqueReturnProperty.add( name ); +// +// final String quotingNormalizedColumnName = normalizeColumnQuoting( propertyresult.column() ); +// +// String key = StringHelper.root( name ); +// ArrayList intermediateResults = propertyResultsTmp.get( key ); +// if ( intermediateResults == null ) { +// intermediateResults = new ArrayList(); +// propertyResultsTmp.put( key, intermediateResults ); +// } +// intermediateResults.add( quotingNormalizedColumnName ); +// } +// +// Map propertyResults = new HashMap(); +// for ( Map.Entry> entry : propertyResultsTmp.entrySet() ) { +// propertyResults.put( +// entry.getKey(), +// entry.getValue().toArray( new String[ entry.getValue().size() ] ) +// ); +// } +// +// if ( !BinderHelper.isEmptyAnnotationValue( entity.discriminatorColumn() ) ) { +// final String quotingNormalizedName = normalizeColumnQuoting( entity.discriminatorColumn() ); +// propertyResults.put( "class", new String[] { quotingNormalizedName } ); +// } +// +// if ( propertyResults.isEmpty() ) { +// propertyResults = java.util.Collections.emptyMap(); +// } +// +// NativeSQLQueryRootReturn result = new NativeSQLQueryRootReturn( +// "alias" + entityAliasIndex++, +// entity.entityClass().getName(), +// propertyResults, +// LockMode.READ +// ); +// definition.addQueryReturn( result ); +// } +// +// for ( ColumnResult column : ann.columns() ) { +// definition.addQueryReturn( +// new NativeSQLQueryScalarReturn( +// normalizeColumnQuoting( column.name() ), +// column.type() != null ? context.getMetadataCollector().getTypeResolver().heuristicType( column.type().getName() ) : null +// ) +// ); +// } +// +// for ( ConstructorResult constructorResult : ann.classes() ) { +// List columnReturns = new ArrayList(); +// for ( ColumnResult columnResult : constructorResult.columns() ) { +// columnReturns.add( +// new NativeSQLQueryScalarReturn( +// normalizeColumnQuoting( columnResult.name() ), +// columnResult.type() != null ? context.getMetadataCollector().getTypeResolver().heuristicType( columnResult.type().getName() ) : null +// ) +// ); +// } +// definition.addQueryReturn( +// new NativeSQLQueryConstructorReturn( constructorResult.targetClass(), columnReturns ) +// ); +// } +// +// if ( isDefault ) { +// context.getMetadataCollector().addDefaultResultSetMapping( definition ); +// } +// else { +// context.getMetadataCollector().addResultSetMapping( definition ); +// } + throw new NotYetImplementedFor6Exception( getClass() ); } private String normalizeColumnQuoting(String name) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/OrdinalParameterDescriptor.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/OrdinalParameterDescriptor.java index c738db0f98..e1a1364e71 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/OrdinalParameterDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/OrdinalParameterDescriptor.java @@ -7,6 +7,7 @@ package org.hibernate.engine.query.spi; import org.hibernate.Incubating; +import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.type.Type; /** @@ -40,4 +41,9 @@ public class OrdinalParameterDescriptor extends AbstractParameterDescriptor { public int getValuePosition() { return valuePosition; } + + @Override + public boolean allowsMultiValuedBinding() { + throw new NotYetImplementedFor6Exception( getClass() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AllowableParameterType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AllowableParameterType.java index d5a12f5f90..0f8b7b32a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AllowableParameterType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AllowableParameterType.java @@ -26,7 +26,5 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @Incubating public interface AllowableParameterType extends Writeable { - default JavaTypeDescriptor getExpressableJavaTypeDescriptor(){ - throw new NotYetImplementedFor6Exception( getClass() ); - } + JavaTypeDescriptor getExpressableJavaTypeDescriptor(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 5e4b294682..506f7d0550 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -11,6 +11,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -229,6 +230,9 @@ public abstract class AbstractCollectionPersister private Map collectionPropertyColumnAliases = new HashMap(); + private final Comparator comparator; + + public AbstractCollectionPersister( Collection collectionBinding, CollectionDataAccess cacheAccessStrategy, @@ -609,9 +613,16 @@ public abstract class AbstractCollectionPersister // manyToManyOrderByTranslation = null; } + comparator = collectionBinding.getComparator(); + initCollectionPropertyMap(); } + @Override + public Comparator getSortingComparator() { + return comparator; + } + protected String determineTableName(Table table, JdbcEnvironment jdbcEnvironment) { if ( table.getSubselect() != null ) { return "( " + table.getSubselect() + " )"; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java index 6e21f10ced..aa508b52de 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java @@ -9,6 +9,7 @@ package org.hibernate.persister.collection; import java.io.Serializable; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Comparator; import java.util.Map; import org.hibernate.HibernateException; @@ -20,6 +21,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGenerator; import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.walking.spi.CollectionDefinition; @@ -320,4 +322,14 @@ public interface CollectionPersister extends CollectionDefinition { * @return the name of the property this collection is mapped by */ String getMappedByProperty(); + + /** + * For sorted collections, the comparator to use. Non-parameterized + * because for SORTED_SET the elements are compared but for SORTED_MAP the + * keys are compared + * + * @see CollectionClassification#SORTED_MAP + * @see CollectionClassification#SORTED_SET + */ + Comparator getSortingComparator(); } diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java index 92e8c012b1..369833b6a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java @@ -28,6 +28,7 @@ import javax.persistence.TemporalType; import javax.persistence.TransactionRequiredException; import org.hibernate.HibernateException; +import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.ScrollMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -383,50 +384,51 @@ public class ProcedureCallImpl // both: (1) add the `? = ` part and also (2) register a REFCURSOR parameter for DBs (Oracle, PGSQL) that // need it. - final String call = getSession().getJdbcServices().getJdbcEnvironment().getDialect().getCallableStatementSupport().renderCallableStatement( - procedureName, - getParameterMetadata(), - paramBindings, - getSession() - ); - - LOG.debugf( "Preparing procedure call : %s", call ); - final CallableStatement statement = (CallableStatement) getSession() - .getJdbcCoordinator() - .getStatementPreparer() - .prepareStatement( call, true ); - - - // prepare parameters - - getParameterMetadata().visitRegistrations( - new Consumer>() { - int i = 1; - - @Override - public void accept(QueryParameter queryParameter) { - try { - final ProcedureParameterImplementor registration = (ProcedureParameterImplementor) queryParameter; - registration.prepare( statement, i, ProcedureCallImpl.this ); - if ( registration.getMode() == ParameterMode.REF_CURSOR ) { - i++; - } - else { - i += registration.getSqlTypes().length; - } - } - catch (SQLException e) { - throw getSession().getJdbcServices().getSqlExceptionHelper().convert( - e, - "Error preparing registered callable parameter", - getProcedureName() - ); - } - } - } - ); - - return new ProcedureOutputsImpl( this, statement ); +// final String call = getSession().getJdbcServices().getJdbcEnvironment().getDialect().getCallableStatementSupport().renderCallableStatement( +// procedureName, +// getParameterMetadata(), +// paramBindings, +// getSession() +// ); +// +// LOG.debugf( "Preparing procedure call : %s", call ); +// final CallableStatement statement = (CallableStatement) getSession() +// .getJdbcCoordinator() +// .getStatementPreparer() +// .prepareStatement( call, true ); +// +// +// // prepare parameters +// +// getParameterMetadata().visitRegistrations( +// new Consumer>() { +// int i = 1; +// +// @Override +// public void accept(QueryParameter queryParameter) { +// try { +// final ProcedureParameterImplementor registration = (ProcedureParameterImplementor) queryParameter; +// registration.prepare( statement, i, ProcedureCallImpl.this ); +// if ( registration.getMode() == ParameterMode.REF_CURSOR ) { +// i++; +// } +// else { +// i += registration.getSqlTypes().length; +// } +// } +// catch (SQLException e) { +// throw getSession().getJdbcServices().getSqlExceptionHelper().convert( +// e, +// "Error preparing registered callable parameter", +// getProcedureName() +// ); +// } +// } +// } +// ); +// +// return new ProcedureOutputsImpl( this, statement ); + throw new NotYetImplementedFor6Exception( getClass() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java index 9143b4bd29..fdefbd562c 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.Objects; import javax.persistence.ParameterMode; +import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport; import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType; @@ -127,117 +128,118 @@ public class ProcedureParameterImpl extends AbstractQueryParameter impleme CallableStatement statement, int startIndex, ProcedureCallImplementor procedureCall) throws SQLException { - final QueryParameterBinding binding = procedureCall.getParameterBindings().getBinding( this ); - - // initially set up the Type we will use for binding as the explicit type. - AllowableParameterType typeToUse = getHibernateType(); - - // however, for Calendar binding with an explicit TemporalType we may need to adjust this... - if ( binding != null && binding.getExplicitTemporalPrecision() != null ) { - typeToUse = ( (AllowableTemporalParameterType) typeToUse ).resolveTemporalPrecision( - binding.getExplicitTemporalPrecision(), - procedureCall.getSession().getFactory().getTypeConfiguration() - ); - } - - this.startIndex = startIndex; - if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) { - if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) { - if ( sqlTypesToUse.length > 1 ) { - // there is more than one column involved; see if the Hibernate Type can handle - // multi-param extraction... - final boolean canHandleMultiParamExtraction = - ProcedureParameterExtractionAware.class.isInstance( typeToUse ) - && ( (ProcedureParameterExtractionAware) typeToUse ).canDoExtraction(); - if ( ! canHandleMultiParamExtraction ) { - // it cannot... - throw new UnsupportedOperationException( - "Type [" + typeToUse + "] does support multi-parameter value extraction" - ); - } - } - // TODO: sqlTypesToUse.length > 1 does not seem to have a working use case (HHH-10769). - // The idea is that an embeddable/custom type can have more than one column values - // that correspond with embeddable/custom attribute value. This does not seem to - // be working yet. For now, if sqlTypesToUse.length > 1, then register - // the out parameters by position (since we only have one name). - // This will cause a failure if there are other parameters bound by - // name and the dialect does not support "mixed" named/positional parameters; - // e.g., Oracle. - if ( sqlTypesToUse.length == 1 && - procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && - canDoNameParameterBinding( typeToUse ) ) { - statement.registerOutParameter( getName(), sqlTypesToUse[0] ); - } - else { - for ( int i = 0; i < sqlTypesToUse.length; i++ ) { - statement.registerOutParameter( startIndex + i, sqlTypesToUse[i] ); - } - } - } - - if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) { - if ( binding == null || binding.getBindValue() == null ) { - // the user did not binding a value to the parameter being processed. This is the condition - // defined by `passNulls` and that value controls what happens here. If `passNulls` is - // {@code true} we will binding the NULL value into the statement; if `passNulls` is - // {@code false} we will not. - // - // Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure - // parameter defines a default value. Deferring to that information would be the best option - if ( isPassNullsEnabled() ) { - log.debugf( - "Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to true; binding NULL", - procedureCall.getProcedureName(), - this - ); - if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) { - ((ProcedureParameterNamedBinder) typeToUse).nullSafeSet( - statement, - null, - this.getName(), - procedureCall.getSession() - ); - } - else { - typeToUse.nullSafeSet( statement, null, startIndex, procedureCall.getSession() ); - } - } - else { - log.debugf( - "Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to false; assuming procedure defines default value", - procedureCall.getProcedureName(), - this - ); - } - } - else { - if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) { - ((ProcedureParameterNamedBinder) typeToUse).nullSafeSet( - statement, - binding.getBindValue(), - this.getName(), - procedureCall.getSession() - ); - } - else { - typeToUse.nullSafeSet( statement, binding.getBindValue(), startIndex, procedureCall.getSession() ); - } - } - } - } - else { - // we have a REF_CURSOR type param - if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED ) { - procedureCall.getSession().getFactory().getServiceRegistry() - .getService( RefCursorSupport.class ) - .registerRefCursorParameter( statement, getName() ); - } - else { - procedureCall.getSession().getFactory().getServiceRegistry() - .getService( RefCursorSupport.class ) - .registerRefCursorParameter( statement, startIndex ); - } - } + throw new NotYetImplementedFor6Exception( getClass() ); +// final QueryParameterBinding binding = procedureCall.getParameterBindings().getBinding( this ); +// +// // initially set up the Type we will use for binding as the explicit type. +// AllowableParameterType typeToUse = getHibernateType(); +// +// // however, for Calendar binding with an explicit TemporalType we may need to adjust this... +// if ( binding != null && binding.getExplicitTemporalPrecision() != null ) { +// typeToUse = ( (AllowableTemporalParameterType) typeToUse ).resolveTemporalPrecision( +// binding.getExplicitTemporalPrecision(), +// procedureCall.getSession().getFactory().getTypeConfiguration() +// ); +// } +// +// this.startIndex = startIndex; +// if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) { +// if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) { +// if ( sqlTypesToUse.length > 1 ) { +// // there is more than one column involved; see if the Hibernate Type can handle +// // multi-param extraction... +// final boolean canHandleMultiParamExtraction = +// ProcedureParameterExtractionAware.class.isInstance( typeToUse ) +// && ( (ProcedureParameterExtractionAware) typeToUse ).canDoExtraction(); +// if ( ! canHandleMultiParamExtraction ) { +// // it cannot... +// throw new UnsupportedOperationException( +// "Type [" + typeToUse + "] does support multi-parameter value extraction" +// ); +// } +// } +// // TODO: sqlTypesToUse.length > 1 does not seem to have a working use case (HHH-10769). +// // The idea is that an embeddable/custom type can have more than one column values +// // that correspond with embeddable/custom attribute value. This does not seem to +// // be working yet. For now, if sqlTypesToUse.length > 1, then register +// // the out parameters by position (since we only have one name). +// // This will cause a failure if there are other parameters bound by +// // name and the dialect does not support "mixed" named/positional parameters; +// // e.g., Oracle. +// if ( sqlTypesToUse.length == 1 && +// procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && +// canDoNameParameterBinding( typeToUse ) ) { +// statement.registerOutParameter( getName(), sqlTypesToUse[0] ); +// } +// else { +// for ( int i = 0; i < sqlTypesToUse.length; i++ ) { +// statement.registerOutParameter( startIndex + i, sqlTypesToUse[i] ); +// } +// } +// } +// +// if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) { +// if ( binding == null || binding.getBindValue() == null ) { +// // the user did not binding a value to the parameter being processed. This is the condition +// // defined by `passNulls` and that value controls what happens here. If `passNulls` is +// // {@code true} we will binding the NULL value into the statement; if `passNulls` is +// // {@code false} we will not. +// // +// // Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure +// // parameter defines a default value. Deferring to that information would be the best option +// if ( isPassNullsEnabled() ) { +// log.debugf( +// "Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to true; binding NULL", +// procedureCall.getProcedureName(), +// this +// ); +// if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) { +// ((ProcedureParameterNamedBinder) typeToUse).nullSafeSet( +// statement, +// null, +// this.getName(), +// procedureCall.getSession() +// ); +// } +// else { +// typeToUse.nullSafeSet( statement, null, startIndex, procedureCall.getSession() ); +// } +// } +// else { +// log.debugf( +// "Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to false; assuming procedure defines default value", +// procedureCall.getProcedureName(), +// this +// ); +// } +// } +// else { +// if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) { +// ((ProcedureParameterNamedBinder) typeToUse).nullSafeSet( +// statement, +// binding.getBindValue(), +// this.getName(), +// procedureCall.getSession() +// ); +// } +// else { +// typeToUse.nullSafeSet( statement, binding.getBindValue(), startIndex, procedureCall.getSession() ); +// } +// } +// } +// } +// else { +// // we have a REF_CURSOR type param +// if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED ) { +// procedureCall.getSession().getFactory().getServiceRegistry() +// .getService( RefCursorSupport.class ) +// .registerRefCursorParameter( statement, getName() ); +// } +// else { +// procedureCall.getSession().getFactory().getServiceRegistry() +// .getService( RefCursorSupport.class ) +// .registerRefCursorParameter( statement, startIndex ); +// } +// } } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java index 8115b3e649..7d761461ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java @@ -130,7 +130,7 @@ public class QueryParameterBindingImpl implements QueryParameterBinding { //noinspection unchecked this.bindType = (AllowableParameterType) BindingTypeHelper.INSTANCE.resolveDateTemporalTypeVariant( - getBindType().getJavaType(), + getBindType().getExpressableJavaTypeDescriptor().getJavaType(), getBindType() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/ResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/ResultSetMappingDescriptor.java index 972f646176..7356132b55 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/ResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/ResultSetMappingDescriptor.java @@ -90,7 +90,7 @@ public interface ResultSetMappingDescriptor { /** * temporary so I can call externally */ - public interface QueryResultDefinition { + interface QueryResultDefinition { // what args? QueryResultBuilder resolve(); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/LoadContexts.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/LoadContexts.java index edec8599d2..c482f50ea4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/LoadContexts.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/LoadContexts.java @@ -16,7 +16,7 @@ import org.hibernate.internal.util.collections.StandardStack; /** * Maintains a Stack of processing state related to performing load operations. - * The state is defined by {@link JdbcValuesSourceProcessingState} which + * The sCollectionLoadContexttate is defined by {@link JdbcValuesSourceProcessingState} which * encapsulates the data to be processed by the load whether the data comes from * a ResultSet or second-level cache hit. * diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java index d73eb34762..c6a06e770f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java @@ -30,6 +30,7 @@ import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.internal.MutableEntityEntryFactory; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.EntityEntryFactory; +import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.ValueInclusion; @@ -628,6 +629,21 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { public boolean canUseReferenceCacheEntries() { return false; } + + @Override + public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) { + return false; + } + + @Override + public boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers) { + return false; + } + + @Override + public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers) { + return false; + } } public static class NoopCollectionPersister implements CollectionPersister { @@ -877,6 +893,11 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { return null; } + @Override + public Comparator getSortingComparator() { + return null; + } + @Override public void processQueuedOps(PersistentCollection collection, Serializable key, SharedSessionContractImplementor session) throws HibernateException {