HHH-16742 fix implementation of TupleMetadata
fix issue when "same" selection item is assigned two different aliases
This commit is contained in:
parent
acf9495af3
commit
c5ecf5d41c
|
@ -11,7 +11,6 @@ import java.time.Instant;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.IdentityHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -128,36 +127,62 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
|
|
||||||
private TupleMetadata getTupleMetadata(List<SqmSelection<?>> selections) {
|
private TupleMetadata getTupleMetadata(List<SqmSelection<?>> selections) {
|
||||||
if ( getQueryOptions().getTupleTransformer() == null ) {
|
if ( getQueryOptions().getTupleTransformer() == null ) {
|
||||||
return new TupleMetadata( buildTupleElementMap( selections ) );
|
return new TupleMetadata( buildTupleElementArray( selections ), buildTupleAliasArray( selections ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer : " +
|
"Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer: "
|
||||||
getQueryOptions().getTupleTransformer()
|
+ getQueryOptions().getTupleTransformer()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<TupleElement<?>, Integer> buildTupleElementMap(List<SqmSelection<?>> selections) {
|
private static TupleElement<?>[] buildTupleElementArray(List<SqmSelection<?>> selections) {
|
||||||
final Map<TupleElement<?>, Integer> tupleElementMap;
|
final TupleElement<?>[] elements;
|
||||||
if ( selections.size() == 1
|
if ( selections.size() == 1 ) {
|
||||||
&& selections.get( 0 ).getSelectableNode() instanceof CompoundSelection<?> ) {
|
final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode();
|
||||||
final List<? extends JpaSelection<?>> selectionItems =
|
if ( selectableNode instanceof CompoundSelection<?> ) {
|
||||||
selections.get( 0 ).getSelectableNode()
|
final List<? extends JpaSelection<?>> selectionItems = selectableNode.getSelectionItems();
|
||||||
.getSelectionItems();
|
elements = new TupleElement<?>[ selectionItems.size() ];
|
||||||
tupleElementMap = new IdentityHashMap<>( selectionItems.size() );
|
|
||||||
for ( int i = 0; i < selectionItems.size(); i++ ) {
|
for ( int i = 0; i < selectionItems.size(); i++ ) {
|
||||||
tupleElementMap.put( selectionItems.get( i ), i );
|
elements[i] = selectionItems.get( i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tupleElementMap = new IdentityHashMap<>( selections.size() );
|
elements = new TupleElement<?>[] { selectableNode };
|
||||||
for (int i = 0; i < selections.size(); i++ ) {
|
|
||||||
final SqmSelection<?> selection = selections.get( i );
|
|
||||||
tupleElementMap.put( selection.getSelectableNode(), i );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tupleElementMap;
|
else {
|
||||||
|
elements = new TupleElement<?>[ selections.size() ];
|
||||||
|
for ( int i = 0; i < selections.size(); i++ ) {
|
||||||
|
elements[i] = selections.get(i).getSelectableNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] buildTupleAliasArray(List<SqmSelection<?>> selections) {
|
||||||
|
final String[] elements;
|
||||||
|
if ( selections.size() == 1 ) {
|
||||||
|
final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode();
|
||||||
|
if ( selectableNode instanceof CompoundSelection<?> ) {
|
||||||
|
final List<? extends JpaSelection<?>> selectionItems = selectableNode.getSelectionItems();
|
||||||
|
elements = new String[ selectionItems.size() ];
|
||||||
|
for ( int i = 0; i < selectionItems.size(); i++ ) {
|
||||||
|
elements[i] = selectionItems.get( i ).getAlias();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elements = new String[] { selectableNode.getAlias() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elements = new String[ selections.size() ];
|
||||||
|
for ( int i = 0; i < selections.size(); i++ ) {
|
||||||
|
elements[i] = selections.get(i).getAlias();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void applyOptions(NamedSqmQueryMemento memento) {
|
protected void applyOptions(NamedSqmQueryMemento memento) {
|
||||||
|
@ -173,8 +198,10 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
|
|
||||||
if ( memento.getParameterTypes() != null ) {
|
if ( memento.getParameterTypes() != null ) {
|
||||||
for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) {
|
for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) {
|
||||||
final QueryParameterImplementor<?> parameter = getParameterMetadata().getQueryParameter( entry.getKey() );
|
final QueryParameterImplementor<?> parameter =
|
||||||
final BasicType<?> type = getSessionFactory().getTypeConfiguration()
|
getParameterMetadata().getQueryParameter( entry.getKey() );
|
||||||
|
final BasicType<?> type =
|
||||||
|
getSessionFactory().getTypeConfiguration()
|
||||||
.getBasicTypeRegistry()
|
.getBasicTypeRegistry()
|
||||||
.getRegisteredType( entry.getValue() );
|
.getRegisteredType( entry.getValue() );
|
||||||
parameter.applyAnticipatedType( type );
|
parameter.applyAnticipatedType( type );
|
||||||
|
|
|
@ -7,51 +7,58 @@
|
||||||
|
|
||||||
package org.hibernate.sql.results.internal;
|
package org.hibernate.sql.results.internal;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import jakarta.persistence.TupleElement;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import jakarta.persistence.TupleElement;
|
|
||||||
|
import static java.util.Collections.unmodifiableMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata about the tuple structure.
|
* Metadata about the tuple structure.
|
||||||
*
|
*
|
||||||
* @author Christian Beikov
|
* @author Christian Beikov
|
||||||
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public final class TupleMetadata {
|
public final class TupleMetadata {
|
||||||
private final Map<TupleElement<?>, Integer> index;
|
private final TupleElement<?>[] elements;
|
||||||
|
private final String[] aliases;
|
||||||
private Map<String, Integer> nameIndex;
|
private Map<String, Integer> nameIndex;
|
||||||
|
private Map<TupleElement<?>, Integer> elementIndex;
|
||||||
private List<TupleElement<?>> list;
|
private List<TupleElement<?>> list;
|
||||||
|
|
||||||
public TupleMetadata(Map<TupleElement<?>, Integer> index) {
|
public TupleMetadata(TupleElement<?>[] elements, String[] aliases) {
|
||||||
this.index = index;
|
this.elements = elements;
|
||||||
|
this.aliases = aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer get(TupleElement<?> tupleElement) {
|
public Integer get(TupleElement<?> element) {
|
||||||
return index.get( tupleElement );
|
if ( elementIndex == null ) {
|
||||||
|
final Map<TupleElement<?>, Integer> map = new IdentityHashMap<>( elements.length );
|
||||||
|
for (int i = 0; i < elements.length; i++ ) {
|
||||||
|
map.put( elements[i], i );
|
||||||
|
}
|
||||||
|
elementIndex = unmodifiableMap( map );
|
||||||
|
}
|
||||||
|
return elementIndex.get( element );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer get(String name) {
|
public Integer get(String name) {
|
||||||
Map<String, Integer> nameIndex = this.nameIndex;
|
|
||||||
if ( nameIndex == null ) {
|
if ( nameIndex == null ) {
|
||||||
nameIndex = new HashMap<>( index.size() );
|
final Map<String, Integer> map = new HashMap<>( aliases.length );
|
||||||
for ( Map.Entry<TupleElement<?>, Integer> entry : index.entrySet() ) {
|
for ( int i = 0; i < aliases.length; i++ ) {
|
||||||
nameIndex.put( entry.getKey().getAlias(), entry.getValue() );
|
map.put( aliases[i], i );
|
||||||
}
|
}
|
||||||
this.nameIndex = nameIndex = Collections.unmodifiableMap( nameIndex );
|
nameIndex = unmodifiableMap( map );
|
||||||
}
|
}
|
||||||
return nameIndex.get( name );
|
return nameIndex.get( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TupleElement<?>> getList() {
|
public List<TupleElement<?>> getList() {
|
||||||
List<TupleElement<?>> list = this.list;
|
|
||||||
if ( list == null ) {
|
if ( list == null ) {
|
||||||
final TupleElement<?>[] array = new TupleElement[index.size()];
|
list = List.of( elements );
|
||||||
for ( Map.Entry<TupleElement<?>, Integer> entry : index.entrySet() ) {
|
|
||||||
array[entry.getValue()] = entry.getKey();
|
|
||||||
}
|
|
||||||
this.list = list = Collections.unmodifiableList( Arrays.asList( array ) );
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue