6 - SQM based on JPA type system
This commit is contained in:
parent
a769d47a9a
commit
f48f486ec6
|
@ -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<FieldResult> properties = new ArrayList<FieldResult>();
|
||||
List<String> propertyNames = new ArrayList<String>();
|
||||
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<String> 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<String> uniqueReturnProperty = new HashSet<String>();
|
||||
Map<String, ArrayList<String>> propertyResultsTmp = new HashMap<String, ArrayList<String>>();
|
||||
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<String> intermediateResults = propertyResultsTmp.get( key );
|
||||
if ( intermediateResults == null ) {
|
||||
intermediateResults = new ArrayList<String>();
|
||||
propertyResultsTmp.put( key, intermediateResults );
|
||||
}
|
||||
intermediateResults.add( quotingNormalizedColumnName );
|
||||
}
|
||||
|
||||
Map<String, String[]> propertyResults = new HashMap<String,String[]>();
|
||||
for ( Map.Entry<String, ArrayList<String>> 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<NativeSQLQueryScalarReturn> columnReturns = new ArrayList<NativeSQLQueryScalarReturn>();
|
||||
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<FieldResult> properties = new ArrayList<FieldResult>();
|
||||
// List<String> propertyNames = new ArrayList<String>();
|
||||
// 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<String> 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<String> uniqueReturnProperty = new HashSet<String>();
|
||||
// Map<String, ArrayList<String>> propertyResultsTmp = new HashMap<String, ArrayList<String>>();
|
||||
// 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<String> intermediateResults = propertyResultsTmp.get( key );
|
||||
// if ( intermediateResults == null ) {
|
||||
// intermediateResults = new ArrayList<String>();
|
||||
// propertyResultsTmp.put( key, intermediateResults );
|
||||
// }
|
||||
// intermediateResults.add( quotingNormalizedColumnName );
|
||||
// }
|
||||
//
|
||||
// Map<String, String[]> propertyResults = new HashMap<String,String[]>();
|
||||
// for ( Map.Entry<String, ArrayList<String>> 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<NativeSQLQueryScalarReturn> columnReturns = new ArrayList<NativeSQLQueryScalarReturn>();
|
||||
// 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) {
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,5 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
@Incubating
|
||||
public interface AllowableParameterType<J> extends Writeable {
|
||||
|
||||
default JavaTypeDescriptor<J> getExpressableJavaTypeDescriptor(){
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
JavaTypeDescriptor<J> getExpressableJavaTypeDescriptor();
|
||||
}
|
||||
|
|
|
@ -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() + " )";
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<R>
|
|||
// 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<QueryParameter<?>>() {
|
||||
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<QueryParameter<?>>() {
|
||||
// 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
|
||||
|
|
|
@ -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<T> extends AbstractQueryParameter<T> 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 );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
|||
|
||||
//noinspection unchecked
|
||||
this.bindType = (AllowableParameterType) BindingTypeHelper.INSTANCE.resolveDateTemporalTypeVariant(
|
||||
getBindType().getJavaType(),
|
||||
getBindType().getExpressableJavaTypeDescriptor().getJavaType(),
|
||||
getBindType()
|
||||
);
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ public interface ResultSetMappingDescriptor {
|
|||
/**
|
||||
* temporary so I can call externally
|
||||
*/
|
||||
public interface QueryResultDefinition {
|
||||
interface QueryResultDefinition {
|
||||
// what args?
|
||||
QueryResultBuilder resolve();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue