Fix some stored procedure and native query issues

This commit is contained in:
Christian Beikov 2022-02-16 14:13:50 +01:00
parent 8ed1ed5159
commit 439788198f
37 changed files with 609 additions and 213 deletions

View File

@ -7,13 +7,15 @@ import jakarta.persistence.Entity;
import jakarta.persistence.EntityResult;
import jakarta.persistence.FieldResult;
import jakarta.persistence.Id;
import jakarta.persistence.NamedStoredProcedureQuery;
import jakarta.persistence.QueryHint;
import jakarta.persistence.SqlResultSetMapping;
import jakarta.persistence.SqlResultSetMappings;
import jakarta.persistence.StoredProcedureParameter;
import org.hibernate.annotations.NamedNativeQuery;
import org.hibernate.c3p0.internal.C3P0ConnectionProvider;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
@ -27,7 +29,7 @@ import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
@RequiresDialect(Oracle8iDialect.class)
@RequiresDialect(OracleDialect.class)
@TestForIssue( jiraKey = "HHH-10256" )
public class OracleSQLCallableStatementProxyTest extends
BaseCoreFunctionalTestCase {
@ -95,19 +97,19 @@ public class OracleSQLCallableStatementProxyTest extends
public void testStoredProcedureOutParameter() {
doInHibernate( this::sessionFactory, session -> {
List<Object[]> persons = session
.createNamedQuery(
"getPerson")
.createNamedStoredProcedureQuery( "getPerson" )
.setParameter(1, 1L)
.getResultList();
assertEquals(1, persons.size());
} );
}
@NamedNativeQuery(
@NamedStoredProcedureQuery(
name = "getPerson",
query = "{ ? = call fn_person( ? ) }",
callable = true,
resultSetMapping = "person"
procedureName = "fn_person",
resultSetMappings = "person",
hints = @QueryHint(name = "org.hibernate.callableFunction", value = "true"),
parameters = @StoredProcedureParameter(type = Long.class)
)
@SqlResultSetMappings({
@SqlResultSetMapping(

View File

@ -153,7 +153,7 @@ public class Identifier implements Comparable<Identifier> {
public static String unQuote(String name) {
assert isQuoted( name );
return name.substring( 1, name.length() - 2 );
return name.substring( 1, name.length() - 1 );
}
/**

View File

@ -288,9 +288,6 @@ public class MetadataBuildingProcess {
processor.postProcessEntityHierarchies();
processor.processResultSetMappings();
processor.processNamedQueries();
processor.finishUp();
for ( MetadataContributor contributor : classLoaderService.loadJavaServices( MetadataContributor.class ) ) {
log.tracef( "Calling MetadataContributor : %s", contributor );
@ -299,6 +296,11 @@ public class MetadataBuildingProcess {
metadataCollector.processSecondPasses( rootMetadataBuildingContext );
// Make sure collections are fully bound before processing named queries as hbm result set mappings require it
processor.processNamedQueries();
processor.finishUp();
if ( options.isXmlMappingEnabled() ) {
final Iterable<AdditionalJaxbMappingProducer> producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class );
if ( producers != null ) {

View File

@ -13,6 +13,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Supplier;
import org.hibernate.LockMode;
@ -27,11 +28,23 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmResultSetMappingType;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.internal.FetchMementoEmbeddableStandard;
import org.hibernate.query.internal.FetchMementoEntityStandard;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.internal.FetchMementoBasicStandard;
import org.hibernate.query.internal.FetchMementoHbmStandard;
@ -47,6 +60,7 @@ import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.named.ResultMemento;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.type.BasicType;
/**
@ -498,6 +512,21 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
this.propertyPathParts = propertyPath.split( "\\." );
this.columnAliases = extractColumnAliases( hbmPropertyMapping, context );
if ( columnAliases.size() > 1 ) {
// We have to reorder the columns according to the property reordering
final Value value = getValue( parent, propertyPath, context );
assert value instanceof Component;
final Component component = (Component) value;
int[] originalPropertyOrder = component.sortProperties();
if ( originalPropertyOrder != null ) {
final String[] originalColumns = columnAliases.toArray( new String[0] );
for ( int i = 0; i < originalPropertyOrder.length; i++ ) {
final int originalIndex = originalPropertyOrder[i];
columnAliases.set( i, originalColumns[originalIndex] );
}
}
}
BootQueryLogging.LOGGER.debugf(
"Creating PropertyFetchDescriptor (%s : %s) for ResultSet mapping - %s",
parent,
@ -506,11 +535,100 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
);
}
private static Value getValue(HbmFetchParent parent, String propertyPath, MetadataBuildingContext context) {
if ( parent instanceof EntityResultDescriptor ) {
final PersistentClass entityBinding = context.getMetadataCollector()
.getEntityBinding( ( (EntityResultDescriptor) parent ).entityName );
Value value = null;
StringTokenizer st = new StringTokenizer( propertyPath, ".", false );
try {
while ( st.hasMoreElements() ) {
final String element = (String) st.nextElement();
if ( value == null ) {
Property identifierProperty = entityBinding.getIdentifierProperty();
if ( identifierProperty != null && identifierProperty.getName().equals( element ) ) {
// we have a mapped identifier property and the root of
// the incoming property path matched that identifier
// property
value = identifierProperty.getValue();
}
else if ( identifierProperty == null && entityBinding.getIdentifierMapper() != null ) {
// we have an embedded composite identifier
try {
identifierProperty = entityBinding.getIdentifierMapper().getProperty( element );
// the root of the incoming property path matched one
// of the embedded composite identifier properties
value = identifierProperty.getValue();
}
catch (MappingException ignore) {
// ignore it...
}
}
if ( value == null ) {
value = entityBinding.getProperty( element ).getValue();
}
}
else if ( value instanceof Component ) {
value = ( (Component) value ).getProperty( element ).getValue();
}
else if ( value instanceof ToOne ) {
value = context.getMetadataCollector()
.getEntityBinding( ( (ToOne) value ).getReferencedEntityName() )
.getProperty( element )
.getValue();
}
else if ( value instanceof OneToMany ) {
value = ( (OneToMany) value ).getAssociatedClass().getProperty( element ).getValue();
}
else {
final Collection collection = (Collection) value;
switch ( element ) {
case "key":
value = collection.getKey();
break;
case "element":
value = collection.getElement();
break;
case "index":
if ( collection instanceof IndexedCollection ) {
value = ( (IndexedCollection) collection ).getIndex();
break;
}
default:
throw new MappingException( "property [" + element + "] not found on collection [" + collection.getRole() + "]" );
}
}
}
return value;
}
catch (MappingException e) {
throw new MappingException( "property [" + propertyPath + "] not found on entity [" + entityBinding.getEntityName() + "]" );
}
}
else if ( parent instanceof CollectionResultDescriptor ) {
final Collection collectionBinding = context.getMetadataCollector()
.getCollectionBinding( ( (CollectionResultDescriptor) parent ).collectionPath.getFullPath() );
return collectionBinding.getElement();
}
else {
assert parent instanceof JoinDescriptor;
final JoinDescriptor joinDescriptor = (JoinDescriptor) parent;
final HbmFetchParent joinParent = joinDescriptor.fetchParentByAliasAccess.get()
.get( joinDescriptor.ownerTableAlias );
return getValue( joinParent, joinDescriptor.propertyPath + "." + propertyPath, context );
}
}
@Override
public String getFetchablePath() {
return propertyPath;
}
public List<String> getColumnAliases() {
return columnAliases;
}
private static List<String> extractColumnAliases(
JaxbHbmNativeQueryPropertyReturnType hbmPropertyMapping,
MetadataBuildingContext context) {
@ -520,7 +638,7 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
final List<String> columnAliases = new ArrayList<>( hbmPropertyMapping.getReturnColumn().size() );
hbmPropertyMapping.getReturnColumn().forEach(
(column) -> columnAliases.add( column.getName() )
column -> columnAliases.add( column.getName() )
);
return columnAliases;
}
@ -552,7 +670,28 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
fetchable = (Fetchable) ( (FetchableContainer) fetchable ).findSubPart( propertyPathParts[i], null );
}
return new FetchMementoBasicStandard( navigablePath, (BasicValuedModelPart) fetchable, columnAliases.get( 0 ) );
if ( fetchable instanceof BasicValuedModelPart ) {
return new FetchMementoBasicStandard(
navigablePath,
(BasicValuedModelPart) fetchable,
columnAliases.get( 0 )
);
}
else if ( fetchable instanceof EntityValuedFetchable ) {
return new FetchMementoEntityStandard(
navigablePath,
(EntityValuedFetchable) fetchable,
columnAliases
);
}
else {
assert fetchable instanceof EmbeddableValuedModelPart;
return new FetchMementoEmbeddableStandard(
navigablePath,
(EmbeddableValuedModelPart) fetchable,
columnAliases
);
}
}
@Override
@ -632,16 +771,26 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
applyFetchJoins( joinDescriptorsAccess, tableAlias, propertyFetchDescriptors );
final Map<String, FetchMemento> fetchDescriptorMap = new HashMap<>();
final List<String> keyColumnNames = new ArrayList<>();
final boolean isPlural = thisAsParentMemento.getFetchableContainer() instanceof PluralAttributeMapping;
propertyFetchDescriptors.forEach(
hbmFetchDescriptor -> fetchDescriptorMap.put(
hbmFetchDescriptor.getFetchablePath(),
hbmFetchDescriptor.resolve( resolutionContext )
)
hbmFetchDescriptor -> {
if ( isPlural && "key".equals( hbmFetchDescriptor.getFetchablePath() ) ) {
keyColumnNames.addAll( ( (PropertyFetchDescriptor) hbmFetchDescriptor ).getColumnAliases() );
}
else {
fetchDescriptorMap.put(
hbmFetchDescriptor.getFetchablePath(),
hbmFetchDescriptor.resolve( resolutionContext )
);
}
}
);
memento = new FetchMementoHbmStandard(
thisAsParentMemento.getNavigablePath(),
ownerTableAlias,
tableAlias,
keyColumnNames,
lockMode,
thisAsParentMemento,
fetchDescriptorMap,
@ -665,7 +814,14 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
final FetchParentMemento ownerMemento = hbmFetchParent.resolveParentMemento( resolutionContext );
final String[] parts = propertyPath.split( "\\." );
NavigablePath navigablePath = ownerMemento.getNavigablePath().append( parts[ 0 ] );
NavigablePath navigablePath;
if ( ownerMemento.getFetchableContainer() instanceof PluralAttributeMapping ) {
navigablePath = ownerMemento.getNavigablePath().append( CollectionPart.Nature.ELEMENT.getName() );
}
else {
navigablePath = ownerMemento.getNavigablePath();
}
navigablePath = navigablePath.append( parts[ 0 ] );
FetchableContainer fetchable = (FetchableContainer) ownerMemento.getFetchableContainer().findSubPart( parts[ 0 ], null );
for ( int i = 1; i < parts.length; i++ ) {

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.boot.query;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -76,10 +77,26 @@ public class NamedNativeQueryDefinitionBuilder extends AbstractNamedQueryBuilder
return this;
}
public String getSqlString() {
return sqlString;
}
public Set<String> getQuerySpaces() {
return querySpaces;
}
public Map<String, String> getParameterTypes() {
return parameterTypes == null ? Collections.emptyMap() : parameterTypes;
}
public String getResultSetMappingName() {
return resultSetMappingName;
}
public String getResultSetMappingClassName() {
return resultSetMappingClassName;
}
public NamedNativeQueryDefinitionBuilder addSynchronizedQuerySpaces(Set<String> querySpaces) {
if ( querySpaces == null || querySpaces.isEmpty() ) {
return this;

View File

@ -1271,6 +1271,12 @@ public class OracleDialect extends Dialect {
return 1;
}
@Override
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
// Not sure if it's a JDBC driver issue, but it doesn't work
return false;
}
@Override
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
return (ResultSet) statement.getObject( name );

View File

@ -884,7 +884,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
return exporter;
}
private class SqlServerSequenceExporter extends StandardSequenceExporter {
private static class SqlServerSequenceExporter extends StandardSequenceExporter {
public SqlServerSequenceExporter(Dialect dialect) {
super( dialect );
@ -900,6 +900,12 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
}
}
@Override
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
// Not sure if it's a JDBC driver issue, but it doesn't work
return false;
}
@Override
public String generatedAs(String generatedAs) {
return " as (" + generatedAs + ") persisted";

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.loader.ast.internal;
import org.hibernate.FlushMode;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.CollectionLoader;
@ -14,6 +15,8 @@ import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.QueryImplementor;
import jakarta.persistence.Parameter;
/**
* @author Steve Ebersole
*/
@ -34,7 +37,9 @@ public class CollectionLoaderNamedQuery implements CollectionLoader {
@Override
public PersistentCollection<?> load(Object key, SharedSessionContractImplementor session) {
final QueryImplementor<PersistentCollection<?>> query = namedQueryMemento.toQuery( session );
query.setParameter( 1, key );
//noinspection unchecked
query.setParameter( (Parameter<Object>) query.getParameters().iterator().next(), key );
query.setHibernateFlushMode( FlushMode.MANUAL );
return query.getResultList().get( 0 );
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.loader.ast.internal;
import org.hibernate.FlushMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
@ -14,6 +15,8 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.QueryImplementor;
import jakarta.persistence.Parameter;
/**
* Implementation of SingleIdEntityLoader for cases where the application has
* provided the select load query
@ -44,7 +47,9 @@ public class SingleIdEntityLoaderProvidedQueryImpl<T> implements SingleIdEntityL
entityDescriptor.getMappedJavaType().getJavaTypeClass()
);
query.setParameter( 1, pkValue );
//noinspection unchecked
query.setParameter( (Parameter<Object>) query.getParameters().iterator().next(), pkValue );
query.setHibernateFlushMode( FlushMode.MANUAL );
return query.uniqueResult();
}

View File

@ -2678,20 +2678,19 @@ public abstract class AbstractEntityPersister
Component component = (Component) property.getValue();
internalInitSubclassPropertyAliasesMap( name, component.getProperties() );
}
else {
String[] aliases = new String[property.getColumnSpan()];
String[] cols = new String[property.getColumnSpan()];
int l = 0;
for ( Selectable selectable: property.getSelectables() ) {
Dialect dialect = getFactory().getJdbcServices().getDialect();
aliases[l] = selectable.getAlias( dialect, property.getValue().getTable() );
cols[l] = selectable.getText(dialect); // TODO: skip formulas?
l++;
}
subclassPropertyAliases.put( name, aliases );
subclassPropertyColumnNames.put( name, cols );
String[] aliases = new String[property.getColumnSpan()];
String[] cols = new String[property.getColumnSpan()];
int l = 0;
for ( Selectable selectable: property.getSelectables() ) {
Dialect dialect = getFactory().getJdbcServices().getDialect();
aliases[l] = selectable.getAlias( dialect, property.getValue().getTable() );
cols[l] = selectable.getText(dialect); // TODO: skip formulas?
l++;
}
subclassPropertyAliases.put( name, aliases );
subclassPropertyColumnNames.put( name, cols );
}
}

View File

@ -10,7 +10,6 @@ import java.sql.CallableStatement;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.procedure.spi.ParameterStrategy;
import org.hibernate.query.spi.ProcedureParameterMetadataImplementor;
import org.hibernate.sql.exec.spi.JdbcCall;
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
@ -22,7 +21,6 @@ public abstract class AbstractStandardCallableStatementSupport implements Callab
String procedureName,
JdbcCall procedureCall,
CallableStatement statement,
ParameterStrategy parameterStrategy,
ProcedureParameterMetadataImplementor parameterMetadata,
SharedSessionContractImplementor session) {
if ( procedureCall.getFunctionReturn() != null ) {

View File

@ -17,6 +17,7 @@ import org.hibernate.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.ProcedureParameterMetadataImplementor;
import org.hibernate.sql.exec.internal.JdbcCallImpl;
import org.hibernate.sql.exec.spi.JdbcCall;
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
import jakarta.persistence.ParameterMode;
@ -38,7 +39,7 @@ public class PostgresCallableStatementSupport extends AbstractStandardCallableSt
final boolean firstParamIsRefCursor = parameterMetadata.getParameterCount() != 0
&& isFirstParameterModeRefCursor( parameterMetadata );
if ( firstParamIsRefCursor ) {
if ( firstParamIsRefCursor || functionReturn != null ) {
// validate that the parameter strategy is positional (cannot mix, and REF_CURSOR is inherently positional)
if ( parameterMetadata.hasNamedParameters() ) {
throw new HibernateException( "Cannot mix named parameters and REF_CURSOR parameter on PostgreSQL" );
@ -46,11 +47,10 @@ public class PostgresCallableStatementSupport extends AbstractStandardCallableSt
}
final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList();
final JdbcCallImpl.Builder builder = new JdbcCallImpl.Builder(
parameterMetadata.hasNamedParameters() ?
ParameterStrategy.NAMED :
ParameterStrategy.POSITIONAL
);
final ParameterStrategy parameterStrategy = parameterMetadata.hasNamedParameters() ?
ParameterStrategy.NAMED :
ParameterStrategy.POSITIONAL;
final JdbcCallImpl.Builder builder = new JdbcCallImpl.Builder( parameterStrategy );
final StringBuilder buffer;
final int offset;
@ -82,9 +82,19 @@ public class PostgresCallableStatementSupport extends AbstractStandardCallableSt
throw new HibernateException(
"PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered" );
}
buffer.append( sep ).append( "?" );
buffer.append( sep );
final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration(
i + offset,
procedureCall
);
if ( registration.getName() != null ) {
buffer.append( ':' ).append( registration.getName() );
}
else {
buffer.append( "?" );
}
sep = ",";
builder.addParameterRegistration( parameter.toJdbcParameterRegistration( i + offset, procedureCall ) );
builder.addParameterRegistration( registration );
}
buffer.append( ")}" );

View File

@ -33,7 +33,6 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.procedure.NoSuchParameterException;
import org.hibernate.procedure.ParameterStrategyException;
import org.hibernate.procedure.ProcedureCall;
@ -591,7 +590,7 @@ public class ProcedureCallImpl<R>
final Map<ProcedureParameter<?>, JdbcCallParameterRegistration> parameterRegistrations = new IdentityHashMap<>();
final List<JdbcCallRefCursorExtractor> refCursorExtractors = new ArrayList<>();
if ( functionReturn != null ) {
if ( call.getFunctionReturn() != null ) {
parameterRegistrations.put( functionReturn, call.getFunctionReturn() );
final JdbcCallRefCursorExtractorImpl refCursorExtractor = call.getFunctionReturn().getRefCursorExtractor();
if ( refCursorExtractor != null ) {
@ -620,7 +619,6 @@ public class ProcedureCallImpl<R>
procedureName,
call,
statement,
parameterMetadata.getParameterStrategy(),
parameterMetadata,
getSession()
);
@ -690,7 +688,7 @@ public class ProcedureCallImpl<R>
// Note that this should actually happen in an executor
try {
int paramBindingPosition = functionReturn == null ? 1 : 2;
int paramBindingPosition = call.getFunctionReturn() == null ? 1 : 2;
for ( JdbcParameterBinder parameterBinder : call.getParameterBinders() ) {
parameterBinder.bindParameterValue(
statement,

View File

@ -201,10 +201,10 @@ public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> impleme
.getJdbcSessionContext()
.getServiceRegistry().getService( JdbcEnvironment.class )
.getExtractedDatabaseMetaData();
return
databaseMetaData.supportsNamedParameters()
&& hibernateType instanceof ProcedureParameterNamedBinder
&& ( (ProcedureParameterNamedBinder<?>) hibernateType ).canDoSetting();
return procedureCall.getFunctionReturn() == null
&& databaseMetaData.supportsNamedParameters()
&& hibernateType instanceof ProcedureParameterNamedBinder
&& ( (ProcedureParameterNamedBinder<?>) hibernateType ).canDoSetting();
}
@Override

View File

@ -18,6 +18,7 @@ import org.hibernate.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.spi.ProcedureParameterMetadataImplementor;
import org.hibernate.sql.exec.internal.JdbcCallImpl;
import org.hibernate.sql.exec.spi.JdbcCall;
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
import jakarta.persistence.ParameterMode;
@ -38,9 +39,11 @@ public class StandardCallableStatementSupport extends AbstractStandardCallableSt
public static final StandardCallableStatementSupport REF_CURSOR_INSTANCE = new StandardCallableStatementSupport( true );
private final boolean supportsRefCursors;
private final boolean implicitReturn;
public StandardCallableStatementSupport(boolean supportsRefCursors) {
this.supportsRefCursors = supportsRefCursors;
this.implicitReturn = !supportsRefCursors;
}
@Override
@ -50,14 +53,13 @@ public class StandardCallableStatementSupport extends AbstractStandardCallableSt
final ProcedureParameterMetadataImplementor parameterMetadata = procedureCall.getParameterMetadata();
final SharedSessionContractImplementor session = procedureCall.getSession();
final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList();
final JdbcCallImpl.Builder builder = new JdbcCallImpl.Builder(
parameterMetadata.hasNamedParameters() ?
ParameterStrategy.NAMED :
ParameterStrategy.POSITIONAL
);
final ParameterStrategy parameterStrategy = functionReturn == null && parameterMetadata.hasNamedParameters() ?
ParameterStrategy.NAMED :
ParameterStrategy.POSITIONAL;
final JdbcCallImpl.Builder builder = new JdbcCallImpl.Builder( parameterStrategy );
final StringBuilder buffer;
final int offset;
if ( functionReturn != null ) {
if ( functionReturn != null && !implicitReturn ) {
offset = 2;
buffer = new StringBuilder( 11 + procedureName.length() + registrations.size() * 2 ).append( "{?=call " );
builder.setFunctionReturn( functionReturn.toJdbcFunctionReturn( session ) );
@ -75,9 +77,19 @@ public class StandardCallableStatementSupport extends AbstractStandardCallableSt
if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
verifyRefCursorSupport( session.getJdbcServices().getJdbcEnvironment().getDialect() );
}
buffer.append( sep ).append( "?" );
buffer.append( sep );
final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration(
i + offset,
procedureCall
);
if ( registration.getName() != null ) {
buffer.append( ':' ).append( registration.getName() );
}
else {
buffer.append( "?" );
}
sep = ",";
builder.addParameterRegistration( parameter.toJdbcParameterRegistration( i + offset, procedureCall ) );
builder.addParameterRegistration( registration );
}
buffer.append( ")}" );

View File

@ -22,7 +22,6 @@ public interface CallableStatementSupport {
String procedureName,
JdbcCall procedureCall,
CallableStatement statement,
ParameterStrategy parameterStrategy,
ProcedureParameterMetadataImplementor parameterMetadata,
SharedSessionContractImplementor session);
}

View File

@ -404,6 +404,8 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
NavigablePath getNavigablePath();
LockMode getLockMode();
/**
* Set the lock mode for this return.
*

View File

@ -39,6 +39,14 @@ public class FetchMementoBasicStandard implements FetchMementoBasic {
return navigablePath;
}
public BasicValuedModelPart getFetchedAttribute() {
return fetchedAttribute;
}
public String getColumnAlias() {
return columnAlias;
}
@Override
public FetchBuilder resolve(
Parent parent,

View File

@ -0,0 +1,55 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.internal;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.complete.CompleteFetchBuilderEmbeddableValuedModelPart;
import org.hibernate.query.spi.NavigablePath;
/**
* @author Christian Beikov
*/
public class FetchMementoEmbeddableStandard implements FetchMemento {
private final NavigablePath navigablePath;
private final EmbeddableValuedModelPart attributeMapping;
private final List<String> columnNames;
public FetchMementoEmbeddableStandard(
NavigablePath navigablePath,
EmbeddableValuedModelPart attributeMapping,
List<String> columnNames) {
this.navigablePath = navigablePath;
this.attributeMapping = attributeMapping;
this.columnNames = columnNames;
}
@Override
public FetchBuilder resolve(
Parent parent,
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
return new CompleteFetchBuilderEmbeddableValuedModelPart( navigablePath, attributeMapping, columnNames );
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
public EmbeddableValuedModelPart getAttributeMapping() {
return attributeMapping;
}
public List<String> getColumnNames() {
return columnNames;
}
}

View File

@ -6,12 +6,16 @@
*/
package org.hibernate.query.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.results.FetchBuilder;
@ -31,6 +35,7 @@ public class FetchMementoHbmStandard implements FetchMemento, FetchMemento.Paren
private final NavigablePath navigablePath;
private final String ownerTableAlias;
private final String tableAlias;
private final List<String> keyColumnNames;
private final LockMode lockMode;
private final FetchParentMemento parent;
private final Map<String, FetchMemento> fetchMementoMap;
@ -40,6 +45,7 @@ public class FetchMementoHbmStandard implements FetchMemento, FetchMemento.Paren
NavigablePath navigablePath,
String ownerTableAlias,
String tableAlias,
List<String> keyColumnNames,
LockMode lockMode,
FetchParentMemento parent,
Map<String, FetchMemento> fetchMementoMap,
@ -47,6 +53,7 @@ public class FetchMementoHbmStandard implements FetchMemento, FetchMemento.Paren
this.navigablePath = navigablePath;
this.ownerTableAlias = ownerTableAlias;
this.tableAlias = tableAlias;
this.keyColumnNames = keyColumnNames;
this.lockMode = lockMode;
this.parent = parent;
this.fetchMementoMap = fetchMementoMap;
@ -64,19 +71,34 @@ public class FetchMementoHbmStandard implements FetchMemento, FetchMemento.Paren
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
final Map<String, FetchBuilder> fetchBuilderMap = new HashMap<>();
fetchMementoMap.forEach(
(attrName, fetchMemento) -> fetchBuilderMap.put(
attrName,
fetchMemento.resolve(this, querySpaceConsumer, context )
)
);
final DynamicResultBuilderEntityStandard resultBuilder;
if ( fetchable instanceof PluralAttributeMapping ) {
resultBuilder = new DynamicResultBuilderEntityStandard(
(EntityMappingType) ( (PluralAttributeMapping) fetchable ).getElementDescriptor().getPartMappingType(),
tableAlias,
navigablePath
);
}
else {
resultBuilder = new DynamicResultBuilderEntityStandard(
( (ToOneAttributeMapping) fetchable ).getEntityMappingType(),
tableAlias,
navigablePath
);
}
return new DynamicFetchBuilderLegacy(
tableAlias,
ownerTableAlias,
fetchable.getFetchableName(),
new ArrayList<>(),
fetchBuilderMap
keyColumnNames,
fetchBuilderMap,
resultBuilder
);
}
}

View File

@ -9,7 +9,6 @@ package org.hibernate.query.named;
import java.util.function.Consumer;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.results.FetchBuilder;
/**

View File

@ -0,0 +1,133 @@
/*
* 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.List;
import java.util.function.BiFunction;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultSetMappingSqlSelection;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import static org.hibernate.query.results.ResultsHelper.impl;
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
/**
* CompleteFetchBuilder for embeddable-valued ModelParts
*
* @author Christian Beikov
*/
public class CompleteFetchBuilderEmbeddableValuedModelPart
implements CompleteFetchBuilder, ModelPartReferenceEmbeddable {
private final NavigablePath navigablePath;
private final EmbeddableValuedModelPart modelPart;
private final List<String> columnAliases;
public CompleteFetchBuilderEmbeddableValuedModelPart(
NavigablePath navigablePath,
EmbeddableValuedModelPart modelPart,
List<String> columnAliases) {
this.navigablePath = navigablePath;
this.modelPart = modelPart;
this.columnAliases = columnAliases;
}
@Override
public FetchBuilder cacheKeyInstance() {
return new CompleteFetchBuilderEmbeddableValuedModelPart(
navigablePath,
modelPart,
List.copyOf( columnAliases )
);
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public EmbeddableValuedModelPart getReferencedPart() {
return modelPart;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
assert fetchPath.equals( navigablePath );
final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState );
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
modelPart.forEachSelectable(
(selectionIndex, selectableMapping) -> {
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, selectableMapping.getContainingTableExpression() );
final String mappedColumn = selectableMapping.getSelectionExpression();
final String columnAlias = columnAliases.get( selectionIndex );
creationStateImpl.resolveSqlSelection(
creationStateImpl.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( tableReference, mappedColumn ),
processingState -> {
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnAlias );
final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition );
return new ResultSetMappingSqlSelection( valuesArrayPosition, selectableMapping.getJdbcMapping() );
}
),
modelPart.getJavaType(),
creationStateImpl.getSessionFactory().getTypeConfiguration()
);
}
);
return parent.generateFetchableFetch(
modelPart,
fetchPath,
FetchTiming.IMMEDIATE,
true,
null,
domainResultCreationState
);
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final CompleteFetchBuilderEmbeddableValuedModelPart that = (CompleteFetchBuilderEmbeddableValuedModelPart) o;
return navigablePath.equals( that.navigablePath )
&& modelPart.equals( that.modelPart )
&& columnAliases.equals( that.columnAliases );
}
@Override
public int hashCode() {
int result = navigablePath.hashCode();
result = 31 * result + modelPart.hashCode();
result = 31 * result + columnAliases.hashCode();
return result;
}
}

View File

@ -24,6 +24,7 @@ import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.ResultSetMappingSqlSelection;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlAliasBaseConstant;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResult;
@ -105,7 +106,9 @@ public class CompleteResultBuilderCollectionStandard implements CompleteResultBu
navigablePath,
tableAlias,
null,
creationStateImpl,
new SqlAliasBaseConstant( tableAlias ),
creationStateImpl.getSqlExpressionResolver(),
creationStateImpl.getFromClauseAccess(),
sessionFactory
);
fromClauseAccess.registerTableGroup( navigablePath, rootTableGroup );

View File

@ -22,6 +22,7 @@ import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlAliasBaseConstant;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
@ -82,6 +83,11 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
return entityDescriptor;
}
@Override
public LockMode getLockMode() {
return lockMode;
}
@Override
public NativeQuery.RootReturn setLockMode(LockMode lockMode) {
throw new UnsupportedOperationException();
@ -131,9 +137,11 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
// since this is only used for result set mappings, the canUseInnerJoins value is irrelevant.
true,
navigablePath,
tableAlias,
null,
null,
impl,
new SqlAliasBaseConstant( tableAlias ),
impl.getSqlExpressionResolver(),
impl.getFromClauseAccess(),
impl.getCreationContext()
)
);
@ -141,7 +149,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
return new EntityResultImpl(
navigablePath,
entityDescriptor,
null,
tableAlias,
lockMode,
(entityResult) -> {
if ( discriminatorFetchBuilder == null ) {

View File

@ -85,7 +85,6 @@ public abstract class AbstractFetchBuilderContainer<T extends AbstractFetchBuild
}
final DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard(
this,
propertyName
);

View File

@ -55,6 +55,8 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
private final Map<String, FetchBuilder> fetchBuilderMap;
private final DynamicResultBuilderEntityStandard resultBuilderEntity;
private LockMode lockMode;
public DynamicFetchBuilderLegacy(
String tableAlias,
String ownerTableAlias,
@ -164,41 +166,41 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
keyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
}
keyDescriptor.forEachSelectable(
(selectionIndex, selectableMapping) -> {
resolveSqlSelection(
columnNames.get( selectionIndex ),
createColumnReferenceKey(
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
selectableMapping.getSelectionExpression()
),
selectableMapping.getJdbcMapping(),
jdbcResultsMetadata,
domainResultCreationState
);
}
);
if ( !columnNames.isEmpty() ) {
keyDescriptor.forEachSelectable(
(selectionIndex, selectableMapping) -> {
resolveSqlSelection(
columnNames.get( selectionIndex ),
createColumnReferenceKey(
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
selectableMapping.getSelectionExpression()
),
selectableMapping.getJdbcMapping(),
jdbcResultsMetadata,
domainResultCreationState
);
}
);
}
// We process the fetch builder such that it contains a resultBuilderEntity before calling this method in ResultSetMappingProcessor
assert resultBuilderEntity != null;
return resultBuilderEntity.buildFetch(
parent,
attributeMapping,
jdbcResultsMetadata,
creationState
);
}
else {
return parent.generateFetchableFetch(
attributeMapping,
fetchPath,
FetchTiming.IMMEDIATE,
true,
null,
domainResultCreationState
);
if ( resultBuilderEntity != null ) {
return resultBuilderEntity.buildFetch(
parent,
attributeMapping,
jdbcResultsMetadata,
creationState
);
}
}
return parent.generateFetchableFetch(
attributeMapping,
parent.resolveNavigablePath( attributeMapping ),
FetchTiming.IMMEDIATE,
true,
null,
domainResultCreationState
);
}
private void resolveSqlSelection(
@ -235,17 +237,21 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
@Override
public NativeQuery.FetchReturn setLockMode(LockMode lockMode) {
return null;
this.lockMode = lockMode;
return this;
}
@Override
public NativeQuery.FetchReturn addProperty(String propertyName, String columnAlias) {
return null;
addProperty( propertyName ).addColumnAlias( columnAlias );
return this;
}
@Override
public NativeQuery.ReturnProperty addProperty(String propertyName) {
return null;
DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( propertyName );
fetchBuilderMap.put( propertyName, fetchBuilder );
return fetchBuilder;
}
@Override

View File

@ -14,6 +14,7 @@ import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.spi.NavigablePath;
@ -38,24 +39,15 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere
public class DynamicFetchBuilderStandard
implements DynamicFetchBuilder, NativeQuery.ReturnProperty {
private final DynamicFetchBuilderContainer container;
private final String fetchableName;
private final List<String> columnNames;
public DynamicFetchBuilderStandard(
DynamicFetchBuilderContainer container,
String fetchableName) {
this.container = container;
public DynamicFetchBuilderStandard(String fetchableName) {
this.fetchableName = fetchableName;
this.columnNames = new ArrayList<>();
}
private DynamicFetchBuilderStandard(
DynamicFetchBuilderContainer container,
String fetchableName,
List<String> columnNames) {
this.container = container;
private DynamicFetchBuilderStandard(String fetchableName, List<String> columnNames) {
this.fetchableName = fetchableName;
this.columnNames = columnNames;
}
@ -63,7 +55,6 @@ public class DynamicFetchBuilderStandard
@Override
public DynamicFetchBuilderStandard cacheKeyInstance() {
return new DynamicFetchBuilderStandard(
container,
fetchableName,
List.copyOf( columnNames )
);
@ -71,7 +62,6 @@ public class DynamicFetchBuilderStandard
public DynamicFetchBuilderStandard cacheKeyInstance(DynamicFetchBuilderContainer container) {
return new DynamicFetchBuilderStandard(
container,
fetchableName,
List.copyOf( columnNames )
);
@ -124,6 +114,17 @@ public class DynamicFetchBuilderStandard
creationStateImpl
);
}
else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
attributeMapping.forEachSelectable( selectableConsumer );
return parent.generateFetchableFetch(
attributeMapping,
fetchPath,
FetchTiming.IMMEDIATE,
false,
null,
creationStateImpl
);
}
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
toOneAttributeMapping.getForeignKeyDescriptor().visitKeySelectables( selectableConsumer );

View File

@ -69,6 +69,11 @@ public class DynamicResultBuilderEntityCalculated implements DynamicResultBuilde
return navigablePath;
}
@Override
public LockMode getLockMode() {
return explicitLockMode;
}
@Override
public NativeQuery.RootReturn setLockMode(LockMode lockMode) {
throw new UnsupportedOperationException();

View File

@ -103,6 +103,11 @@ public class DynamicResultBuilderEntityStandard
return navigablePath;
}
@Override
public LockMode getLockMode() {
return lockMode;
}
@Override
public NativeQuery.RootReturn addIdColumnAliases(String... aliases) {
if ( idColumnNames == null ) {
@ -153,7 +158,7 @@ public class DynamicResultBuilderEntityStandard
return buildResultOrFetch(
(tableGroup) -> parent.generateFetchableFetch(
fetchable,
navigablePath,
parent.resolveNavigablePath( fetchable ),
FetchTiming.IMMEDIATE,
true,
null,

View File

@ -173,16 +173,17 @@ public class ParameterParser {
}
private static void checkIsNotAFunctionCall(String sqlString) {
if ( !( sqlString.startsWith( "{" ) && sqlString.endsWith( "}" ) ) ) {
final String trimmed = sqlString.trim();
if ( !( trimmed.startsWith( "{" ) && trimmed.endsWith( "}" ) ) ) {
return;
}
final int chopLocation = sqlString.indexOf( "call" );
final int chopLocation = trimmed.indexOf( "call" );
if ( chopLocation <= 0 ) {
return;
}
final String checkString = sqlString.substring( 1, chopLocation + 4 );
final String checkString = trimmed.substring( 1, chopLocation + 4 );
final String fixture = "?=call";
int fixturePosition = 0;
boolean matches = true;

View File

@ -13,6 +13,7 @@ import java.util.List;
import java.util.Map;
import org.hibernate.QueryException;
import org.hibernate.engine.query.ParameterRecognitionException;
import org.hibernate.query.internal.QueryParameterNamedImpl;
import org.hibernate.query.internal.QueryParameterPositionalImpl;
import org.hibernate.query.spi.QueryParameterImplementor;
@ -125,7 +126,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
parameterStyle = ParameterStyle.NAMED;
}
else if ( parameterStyle != ParameterStyle.NAMED ) {
throw new IllegalStateException( "Cannot mix parameter styles between JDBC-style, ordinal and named in the same query" );
throw new ParameterRecognitionException( "Cannot mix parameter styles between JDBC-style, ordinal and named in the same query" );
}
QueryParameterImplementor<?> parameter = null;

View File

@ -17,6 +17,7 @@ import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
@ -233,6 +234,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
alias2Persister.get( fetchBuilder.getTableAlias() ).findContainingEntityMapping(),
fetchBuilder.getTableAlias(),
suffix,
null,
determineNavigablePath( fetchBuilder )
);
final SQLLoadable loadable = (SQLLoadable) alias2Persister.get( fetchBuilder.getOwnerAlias() );
@ -296,6 +298,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
rootReturn.getEntityMapping(),
rootReturn.getTableAlias(),
suffix,
rootReturn.getLockMode(),
new NavigablePath( rootReturn.getEntityMapping().getEntityName() )
);
}
@ -304,6 +307,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
EntityMappingType entityMapping,
String tableAlias,
String suffix,
LockMode lockMode,
NavigablePath navigablePath) {
final SQLLoadable loadable = (SQLLoadable) entityMapping.getEntityPersister();
final DynamicResultBuilderEntityStandard resultBuilderEntity = new DynamicResultBuilderEntityStandard(
@ -311,6 +315,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
tableAlias,
navigablePath
);
resultBuilderEntity.setLockMode( lockMode );
final String[] identifierAliases = loadable.getIdentifierAliases( suffix );
resultBuilderEntity.addIdColumnAliases( identifierAliases );

View File

@ -49,6 +49,11 @@ public class JdbcCallParameterRegistrationImpl implements JdbcCallParameterRegis
this.refCursorExtractor = refCursorExtractor;
}
@Override
public String getName() {
return name;
}
@Override
public JdbcParameterBinder getParameterBinder() {
return parameterBinder;

View File

@ -18,6 +18,9 @@ import org.hibernate.sql.exec.internal.JdbcCallRefCursorExtractorImpl;
* @author Steve Ebersole
*/
public interface JdbcCallParameterRegistration {
String getName();
ParameterMode getParameterMode();
void registerParameter(

View File

@ -12,6 +12,7 @@ import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.ResultListTransformer;
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.persister.entity.EntityPersister;
@ -124,6 +125,13 @@ public class ListResultsConsumer<R> implements ResultsConsumer<List<R>, R> {
persistenceContext.getLoadContexts().deregister( jdbcValuesSourceProcessingState );
}
//noinspection unchecked
final ResultListTransformer<R> resultListTransformer = (ResultListTransformer<R>) jdbcValuesSourceProcessingState.getExecutionContext()
.getQueryOptions()
.getResultListTransformer();
if ( resultListTransformer != null ) {
return resultListTransformer.transformList( results );
}
return results;
}
catch (RuntimeException e) {

View File

@ -1,87 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.annotations.entity;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
/**
* Used to persist and retrieve objects of type 'PhoneNumber'
*
* @author Sharath Reddy
*/
public class PhoneNumberType implements UserType {
public int[] sqlTypes() {
return new int[]{Types.VARCHAR};
}
public Class<?> returnedClass() {
return PhoneNumber.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
return ( x == y ) || ( x != null && x.equals( y ) );
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
@Override
public Object nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
String result = rs.getString( position );
if ( rs.wasNull() ) return null;
if (result.length() <= 6) {
return new PhoneNumber(result);
}
else {
return new OverseasPhoneNumber(result);
}
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
if ( value == null ) {
st.setNull( index, sqlTypes()[0] );
return;
}
PhoneNumber phoneNumber = (PhoneNumber) value;
String number = phoneNumber.getNumber();
st.setString( index, number);
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}

View File

@ -44,7 +44,6 @@ import static org.hibernate.jpa.HibernateHints.HINT_CALLABLE_FUNCTION;
@NamedNativeQuery(
name = "fn_person_and_phones_hana",
query = "select \"pr.id\", \"pr.name\", \"pr.nickName\", \"pr.address\", \"pr.createdOn\", \"pr.version\", \"ph.id\", \"ph.person_id\", \"ph.phone_number\", \"ph.valid\" from fn_person_and_phones( ? )",
callable = false,
resultSetMapping = "person_with_phones_hana"
)
@SqlResultSetMappings({