HHH-15929 Handle the possibility of different JdbcMappings for the same column

This commit is contained in:
Christian Beikov 2023-05-31 10:49:11 +02:00
parent 3e56e0c6af
commit 5fb312e558
44 changed files with 580 additions and 190 deletions

View File

@ -360,7 +360,7 @@ public class OracleLegacySqlAstTranslator<T extends JdbcOperation> extends Abstr
}
final QuerySpec subquery = new QuerySpec( false, 1 );
for ( ColumnReference idColumnReference : idColumnReferences ) {
subquery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, -1, idColumnReference ) );
subquery.getSelectClause().addSqlSelection( new SqlSelectionImpl( idColumnReference ) );
}
subquery.getFromClause().addRoot( rootTableGroup );
subquery.applyPredicate( querySpec.getWhereClauseRestrictions() );

View File

@ -308,7 +308,7 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends SqlAstTrans
}
final QuerySpec subquery = new QuerySpec( false, 1 );
for ( ColumnReference idColumnReference : idColumnReferences ) {
subquery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, -1, idColumnReference ) );
subquery.getSelectClause().addSqlSelection( new SqlSelectionImpl( idColumnReference ) );
}
subquery.getFromClause().addRoot( rootTableGroup );
subquery.applyPredicate( querySpec.getWhereClauseRestrictions() );

View File

@ -147,7 +147,6 @@ public class AggregateWindowEmulationQueryTransformer implements QueryTransforme
columnNames.add( columnName );
selectClause.addSqlSelection(
new ResolvedSqlSelection(
i + 1,
i,
finalExpression,
(BasicType<Object>) mapping.getJdbcMapping()
@ -193,7 +192,6 @@ public class AggregateWindowEmulationQueryTransformer implements QueryTransforme
);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(
subValuesPosition + 1,
subValuesPosition,
realExpression,
(BasicType<Object>) jdbcMapping
@ -254,7 +252,6 @@ public class AggregateWindowEmulationQueryTransformer implements QueryTransforme
);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(
subValuesPosition + 1,
subValuesPosition,
realExpression,
(BasicType<Object>) jdbcMapping
@ -312,7 +309,6 @@ public class AggregateWindowEmulationQueryTransformer implements QueryTransforme
);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(
subValuesPosition + 1,
subValuesPosition,
realExpression,
(BasicType<Object>) jdbcMapping
@ -352,7 +348,6 @@ public class AggregateWindowEmulationQueryTransformer implements QueryTransforme
columnNames.add( columnName );
subSelectClause.addSqlSelection(
new ResolvedSqlSelection(
oldValueIndex + 1,
oldValueIndex,
sortExpression,
(BasicType<Object>) mapping.getJdbcMapping()

View File

@ -1186,7 +1186,6 @@ public class LoaderSelectBuilder {
);
subQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
valuesPosition + 1,
valuesPosition,
expression
)

View File

@ -6,7 +6,9 @@
*/
package org.hibernate.metamodel.mapping;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.IntFunction;
/**
* Consumer used to visit selectable (column/formula) mappings
@ -157,7 +159,7 @@ public interface SelectableConsumer {
* Very limited functionality in terms of the visited SelectableMappings
* will not have any defined JdbcMapping, etc
*/
default void accept(String tableName, String[] columnNames) {
default void accept(String tableName, String[] columnNames, IntFunction<JdbcMapping> jdbcMappings) {
class SelectableMappingIterator implements SelectableMapping {
private int index;
@ -229,7 +231,7 @@ public interface SelectableConsumer {
@Override
public JdbcMapping getJdbcMapping() {
return null;
return jdbcMappings.apply( index );
}
}
for (

View File

@ -69,7 +69,11 @@ public abstract class AbstractDomainPath implements DomainPath {
selection.getContainingTableExpression()
);
return creationState.getSqlExpressionResolver().resolveSqlExpression(
createColumnReferenceKey( tableReference, selection.getSelectionExpression() ),
createColumnReferenceKey(
tableReference,
selection.getSelectionExpression(),
selection.getJdbcMapping()
),
processingState -> new ColumnReference(
tableReference,
selection
@ -250,7 +254,11 @@ public abstract class AbstractDomainPath implements DomainPath {
SqlAstCreationState creationState) {
final TableReference tableReference = tableGroup.resolveTableReference( getNavigablePath(), selection.getContainingTableExpression() );
final Expression expression = creationState.getSqlExpressionResolver().resolveSqlExpression(
createColumnReferenceKey( tableReference, selection.getSelectionExpression() ),
createColumnReferenceKey(
tableReference,
selection.getSelectionExpression(),
selection.getJdbcMapping()
),
processingState -> new ColumnReference(
tableReference,
selection
@ -271,7 +279,6 @@ public abstract class AbstractDomainPath implements DomainPath {
if ( selectClause.isDistinct() && selectClauseDoesNotContainOrderExpression( expression, selectClause ) ) {
final int valuesArrayPosition = selectClause.getSqlSelections().size();
SqlSelection sqlSelection = new SqlSelectionImpl(
valuesArrayPosition + 1,
valuesArrayPosition,
expression
);

View File

@ -108,7 +108,11 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
SqlAstCreationState creationState) {
final SqlExpressionResolver expressionResolver = creationState.getSqlExpressionResolver();
return expressionResolver.resolveSqlExpression(
createColumnReferenceKey( tableGroup.getPrimaryTableReference(), getSelectionExpression() ),
createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getSelectionExpression(),
jdbcMappingToUse
),
sqlAstProcessingState -> createCaseSearchedExpression( tableGroup )
);
}

View File

@ -21,6 +21,9 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SortSpecification;
import org.hibernate.type.NullType;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/**
* Represents a column-reference used in an order-by fragment
@ -53,13 +56,10 @@ public class ColumnReference implements OrderingExpression, SequencePart {
TableGroup tableGroup,
String modelPartName,
SqlAstCreationState creationState) {
TableReference tableReference;
tableReference = getTableReference( tableGroup );
final TableReference tableReference = getTableReference( tableGroup );
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
return sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( tableReference, columnExpression ),
createColumnReferenceKey( tableReference, columnExpression, NullType.INSTANCE ),
sqlAstProcessingState -> new org.hibernate.sql.ast.tree.expression.ColumnReference(
tableReference,
columnExpression,

View File

@ -920,7 +920,6 @@ public abstract class AbstractCollectionPersister
i,
new SqlSelectionImpl(
i,
i + 1,
new AliasedExpression( sqlSelections.get( i ).getExpression(), keyAlias + columnSuffix )
)
);
@ -933,7 +932,6 @@ public abstract class AbstractCollectionPersister
i,
new SqlSelectionImpl(
i,
i + 1,
new AliasedExpression( sqlSelections.get( i ).getExpression(), indexAlias + columnSuffix )
)
);
@ -945,7 +943,6 @@ public abstract class AbstractCollectionPersister
i,
new SqlSelectionImpl(
i,
i + 1,
new AliasedExpression( sqlSelections.get( i ).getExpression(), identifierColumnAlias + columnSuffix )
)
);
@ -958,7 +955,6 @@ public abstract class AbstractCollectionPersister
i,
new SqlSelectionImpl(
sqlSelection.getValuesArrayPosition(),
sqlSelection.getJdbcResultSetIndex(),
new AliasedExpression( sqlSelection.getExpression(), elementColumnAliases[columnIndex] + columnSuffix )
)
);

View File

@ -1353,7 +1353,11 @@ public abstract class AbstractEntityPersister
(columnIndex, selection) -> {
final String rootPkColumnName = pkColumnNames[ columnIndex ];
final Expression pkColumnExpression = creationState.getSqlExpressionResolver().resolveSqlExpression(
createColumnReferenceKey( rootTableReference, rootPkColumnName ),
createColumnReferenceKey(
rootTableReference,
rootPkColumnName,
selection.getJdbcMapping()
),
sqlAstProcessingState -> new ColumnReference(
rootTableReference.getIdentificationVariable(),
rootPkColumnName,
@ -1365,7 +1369,11 @@ public abstract class AbstractEntityPersister
final String fkColumnName = fkColumnNames[ columnIndex ];
final Expression fkColumnExpression = creationState.getSqlExpressionResolver().resolveSqlExpression(
createColumnReferenceKey( joinedTableReference, fkColumnName ),
createColumnReferenceKey(
joinedTableReference,
fkColumnName,
selection.getJdbcMapping()
),
sqlAstProcessingState -> new ColumnReference(
joinedTableReference.getIdentificationVariable(),
fkColumnName,
@ -1738,7 +1746,6 @@ public abstract class AbstractEntityPersister
i,
new SqlSelectionImpl(
i,
i + 1,
new AliasedExpression( sqlSelections.get( i ).getExpression(), identifierAlias + suffix )
)
);
@ -1750,7 +1757,6 @@ public abstract class AbstractEntityPersister
i,
new SqlSelectionImpl(
i,
i + 1,
new AliasedExpression( sqlSelections.get( i ).getExpression(), getDiscriminatorAlias() + suffix )
)
);
@ -1762,7 +1768,6 @@ public abstract class AbstractEntityPersister
i,
new SqlSelectionImpl(
i,
i + 1,
new AliasedExpression( sqlSelections.get( i ).getExpression(), ROWID_ALIAS + suffix )
)
);
@ -1783,7 +1788,6 @@ public abstract class AbstractEntityPersister
i,
new SqlSelectionImpl(
sqlSelection.getValuesArrayPosition(),
sqlSelection.getJdbcResultSetIndex(),
new AliasedExpression( sqlSelection.getExpression(), selectAlias )
)
);
@ -2990,14 +2994,16 @@ public abstract class AbstractEntityPersister
discriminatorExpression = getDiscriminatorFormulaTemplate();
columnReferenceKey = createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getDiscriminatorFormulaTemplate()
getDiscriminatorFormulaTemplate(),
getDiscriminatorType()
);
}
else {
discriminatorExpression = getDiscriminatorColumnName();
columnReferenceKey = createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getDiscriminatorColumnName()
getDiscriminatorColumnName(),
getDiscriminatorType()
);
}

View File

@ -1417,7 +1417,11 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final int tablePosition = i;
consumer.consume(
tableName,
() -> columnConsumer -> columnConsumer.accept( tableName, constraintOrderedKeyColumnNames[tablePosition] )
() -> columnConsumer -> columnConsumer.accept(
tableName,
constraintOrderedKeyColumnNames[tablePosition],
getIdentifierMapping()::getJdbcMapping
)
);
}
}

View File

@ -759,7 +759,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
tableName,
() -> columnConsumer -> columnConsumer.accept(
tableName,
constraintOrderedKeyColumnNames[tablePosition]
constraintOrderedKeyColumnNames[tablePosition],
getIdentifierMapping()::getJdbcMapping
)
);
}

View File

@ -436,7 +436,11 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
final int tablePosition = i;
consumer.consume(
tableName,
() -> columnConsumer -> columnConsumer.accept( tableName, constraintOrderedKeyColumnNames[tablePosition] )
() -> columnConsumer -> columnConsumer.accept(
tableName,
constraintOrderedKeyColumnNames[tablePosition],
getIdentifierMapping()::getJdbcMapping
)
);
}
}

View File

@ -358,7 +358,8 @@ public class AnonymousTupleEntityValuedModelPart
(ColumnReference) sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableReference,
keyMappings.get( i ).getSelectionExpression()
keyMappings.get( i ).getSelectionExpression(),
keyMappings.get( i ).getJdbcMapping()
),
state -> new ColumnReference(
tableReference,
@ -378,7 +379,8 @@ public class AnonymousTupleEntityValuedModelPart
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableReference,
targetMappings.get( i ).getSelectionExpression()
targetMappings.get( i ).getSelectionExpression(),
targetMappings.get( i ).getJdbcMapping()
),
state -> new ColumnReference(
tableReference,

View File

@ -66,11 +66,6 @@ public class ResultSetMappingSqlSelection implements SqlSelection, Expression, S
return valuesArrayPosition;
}
@Override
public int getJdbcResultSetIndex() {
return valuesArrayPosition + 1;
}
@Override
public Expression getExpression() {
return this;
@ -81,6 +76,11 @@ public class ResultSetMappingSqlSelection implements SqlSelection, Expression, S
return valueMapping;
}
@Override
public boolean isVirtual() {
return false;
}
@Override
public void accept(SqlAstWalker sqlAstWalker) {
throw new UnsupportedOperationException();

View File

@ -91,7 +91,22 @@ public class SelfRenderingFunctionSqlAstExpression
return new SqlSelectionImpl(
jdbcPosition,
valuesArrayPosition,
this
this,
false
);
}
@Override
public SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
boolean virtual,
TypeConfiguration typeConfiguration) {
return new SqlSelectionImpl(
jdbcPosition,
valuesArrayPosition,
this,
virtual
);
}

View File

@ -165,7 +165,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
sqmInterpretation.getSqlExpressionResolver(),
factory
);
matchingIdSubQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, fkTargetColumnExpression ) );
matchingIdSubQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, fkTargetColumnExpression ) );
matchingIdSubQuery.getFromClause().addRoot(
tableGroup

View File

@ -169,7 +169,6 @@ public class MatchingIdSelectionHelper {
idSelectionQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
position,
position + 1,
expression
)
);

View File

@ -174,7 +174,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
( (SqlExpressible) count).getJdbcMapping()
)
);
querySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, count ) );
querySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, count ) );
querySpec.getFromClause().addRoot(
new CteTableGroup(
new NamedTableReference(
@ -280,7 +280,6 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
final CteColumn cteColumn = cteColumns.get( i );
subQuerySelectClause.addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
new ColumnReference(
idSelectTableReference,
@ -295,7 +294,6 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
fkModelPart.forEachSelectable(
(selectionIndex, selectableMapping) -> subQuerySelectClause.addSqlSelection(
new SqlSelectionImpl(
selectionIndex + 1,
selectionIndex,
new ColumnReference(
idSelectTableReference,

View File

@ -282,7 +282,6 @@ public class CteInsertHandler implements InsertHandler {
if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecution() ) {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
SqmInsertStrategyHelper.createRowNumberingExpression(
querySpec,
@ -312,7 +311,6 @@ public class CteInsertHandler implements InsertHandler {
columnNames.add( columnReference.getColumnExpression() );
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
columnReference.getQualifier().equals( valuesAlias )
? columnReference
@ -420,7 +418,6 @@ public class CteInsertHandler implements InsertHandler {
);
rowsWithSequenceQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
rowNumberColumnReference
)
@ -431,7 +428,6 @@ public class CteInsertHandler implements InsertHandler {
);
rowsWithSequenceQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
2,
1,
new SelfRenderingSqlFragmentExpression( fragment )
)
@ -502,7 +498,6 @@ public class CteInsertHandler implements InsertHandler {
entityQuery.getFromClause().addRoot( baseTableGroup );
entityQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new BinaryArithmeticExpression(
new ColumnReference(
@ -546,7 +541,6 @@ public class CteInsertHandler implements InsertHandler {
final CteColumn cteColumn = cteColumns.get( i );
entityQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
new ColumnReference(
"e",
@ -622,7 +616,7 @@ public class CteInsertHandler implements InsertHandler {
( (SqlExpressible) count).getJdbcMapping()
)
);
querySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, count ) );
querySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, count ) );
querySpec.getFromClause().addRoot(
new CteTableGroup(
new NamedTableReference(
@ -877,7 +871,6 @@ public class CteInsertHandler implements InsertHandler {
final CteColumn idCteColumn = cteColumns.get( 0 );
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
"t",
@ -893,7 +886,6 @@ public class CteInsertHandler implements InsertHandler {
final CteColumn cteColumn = cteColumns.get( j );
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
"e",
@ -933,14 +925,12 @@ public class CteInsertHandler implements InsertHandler {
);
finalResultQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
idColumnReference
)
);
finalResultQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
SqmInsertStrategyHelper.createRowNumberingExpression(
querySpec,
@ -987,7 +977,6 @@ public class CteInsertHandler implements InsertHandler {
);
insertSelectSpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
"e",
@ -1021,7 +1010,6 @@ public class CteInsertHandler implements InsertHandler {
final ColumnReference columnReference = assignmentReferences.get( j );
insertSelectSpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
"e",

View File

@ -203,8 +203,6 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
final QuerySpec existsQuerySpec = new QuerySpec( false );
existsQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
-1,
0,
new QueryLiteral<>(
1,
factory.getTypeConfiguration().getBasicTypeForJavaType( Integer.class )
@ -243,8 +241,6 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
targetColumnReferences.addAll( assignment.getAssignable().getColumnReferences() );
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
0,
-1,
assignment.getAssignedValue()
)
);

View File

@ -450,7 +450,7 @@ public class InlineUpdateHandler implements UpdateHandler {
)
);
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl( 1, 0, valuesColumnReference )
new SqlSelectionImpl( 0, valuesColumnReference )
);
}
);
@ -482,7 +482,7 @@ public class InlineUpdateHandler implements UpdateHandler {
)
);
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl( 1, 0, valuesColumnReference )
new SqlSelectionImpl( 0, valuesColumnReference )
);
}
final ValuesTableGroup valuesTableGroup = new ValuesTableGroup(
@ -528,8 +528,6 @@ public class InlineUpdateHandler implements UpdateHandler {
targetColumnReferences.addAll( assignment.getAssignable().getColumnReferences() );
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
0,
-1,
assignment.getAssignedValue()
)
);

View File

@ -91,15 +91,14 @@ public final class ExecuteWithTemporaryTableHelper {
matchingIdSelection.getFromClause().addRoot( mutatingTableGroup );
mutatingEntityDescriptor.getIdentifierMapping().forEachSelectable(
(jdbcPosition, selection) -> {
(selectionIndex, selection) -> {
final TableReference tableReference = mutatingTableGroup.resolveTableReference(
mutatingTableGroup.getNavigablePath(),
selection.getContainingTableExpression()
);
matchingIdSelection.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
jdbcPosition,
jdbcPosition + 1,
selectionIndex,
sqmConverter.getSqlExpressionResolver().resolveSqlExpression(
tableReference,
selection
@ -114,7 +113,6 @@ public final class ExecuteWithTemporaryTableHelper {
matchingIdSelection.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
jdbcPosition,
jdbcPosition + 1,
new QueryLiteral<>(
UUID.fromString( sessionUidAccess.apply( executionContext.getSession() ) ),
(BasicValuedMapping) idTable.getSessionUidColumn().getJdbcMapping()
@ -222,7 +220,6 @@ public final class ExecuteWithTemporaryTableHelper {
if ( temporaryTableColumn != idTable.getSessionUidColumn() ) {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
new ColumnReference(
tableReference,
@ -241,7 +238,6 @@ public final class ExecuteWithTemporaryTableHelper {
(i, selectableMapping) -> {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
new ColumnReference(
tableReference,

View File

@ -58,7 +58,6 @@ public final class ExecuteWithoutIdTableHelper {
final SqlSelection sqlSelection = new SqlSelectionImpl(
// irrelevant
0,
0,
columnReference
);
matchingIdSelect.getSelectClause().addSqlSelection( sqlSelection );

View File

@ -339,7 +339,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
for ( ColumnReference columnReference : assignable.getColumnReferences() ) {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
updatingTableReference.getIdentificationVariable(),
@ -369,7 +368,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
identifierMapping.getJdbcMapping()
);
idSelectQuerySpec.getSelectClause()
.addSqlSelection( new SqlSelectionImpl( 1, 0, columnReference ) );
.addSqlSelection( new SqlSelectionImpl( 0, columnReference ) );
idSelectQuerySpec.addSortSpecification(
new SortSpecification(
columnReference,
@ -528,7 +527,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
);
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
updatingTableReference.getIdentificationVariable(),
@ -689,7 +687,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
updatingTableReference.getIdentificationVariable(),
@ -734,7 +731,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
);
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new ColumnReference(
updatingTableReference.getIdentificationVariable(),

View File

@ -219,7 +219,6 @@ public class TableBasedInsertHandler implements InsertHandler {
targetPathColumns.add( new Assignment( columnReference, columnReference ) );
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
SqmInsertStrategyHelper.createRowNumberingExpression(
querySpec,
@ -237,13 +236,12 @@ public class TableBasedInsertHandler implements InsertHandler {
null,
sessionUidColumn.getJdbcMapping()
);
insertStatement.getTargetColumns().add( sessionUidColumnReference );
targetPathColumns.add( new Assignment( sessionUidColumnReference, sessionUidParameter ) );
querySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl(
insertStatement.getTargetColumns().size(),
insertStatement.getTargetColumns().size() - 1,
sessionUidParameter
) );
insertStatement.getTargetColumns().add( sessionUidColumnReference );
targetPathColumns.add( new Assignment( sessionUidColumnReference, sessionUidParameter ) );
}
}
);

View File

@ -345,7 +345,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
for ( Assignment assignment : assignments ) {
targetColumnReferences.addAll( assignment.getAssignable().getColumnReferences() );
insertSourceSelectQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl( 0, -1, assignment.getAssignedValue() )
new SqlSelectionImpl( assignment.getAssignedValue() )
);
}
@ -380,8 +380,6 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
final QuerySpec existsSubQuerySpec = new QuerySpec( false );
existsSubQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
-1,
0,
new QueryLiteral<>(
1,
sessionFactory.getTypeConfiguration().getBasicTypeForJavaType( Integer.class )

View File

@ -1477,14 +1477,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( versionExpression != null ) {
if ( versionSelection == null ) {
// The position is irrelevant as this is only needed for insert
versionSelection = new SqlSelectionImpl( 1, 0, versionExpression );
versionSelection = new SqlSelectionImpl( 0, versionExpression );
}
selectClause.addSqlSelection( versionSelection );
}
if ( discriminatorExpression != null ) {
if ( discriminatorSelection == null ) {
// The position is irrelevant as this is only needed for insert
discriminatorSelection = new SqlSelectionImpl( 1, 0, discriminatorExpression );
discriminatorSelection = new SqlSelectionImpl( 0, discriminatorExpression );
}
selectClause.addSqlSelection( discriminatorSelection );
}
@ -1504,7 +1504,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return false;
}
identifierSelection = new SqlSelectionImpl(
1,
0,
SqmInsertStrategyHelper.createRowNumberingExpression( querySpec, sessionFactory )
);
@ -1518,7 +1517,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
// The position is irrelevant as this is only needed for insert
identifierSelection = new SqlSelectionImpl(
1,
0,
new SelfRenderingSqlFragmentExpression( fragment )
);
@ -2368,7 +2366,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
new QueryLiteral<>(
selection.getValuesArrayPosition(),
basicType( Integer.class )
)
),
false
)
)
);
@ -4468,7 +4467,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
integerType,
integerType
);
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, expression ) );
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, expression ) );
subQuerySpec.applyPredicate(
pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(
@ -4652,7 +4651,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
).getJdbcMapping(),
modelPart
);
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, expression ) );
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, expression ) );
NavigablePath parent = pluralPartPath.getPluralDomainPath().getNavigablePath().getParent();
subQuerySpec.applyPredicate(
@ -4786,7 +4785,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
for ( int i = 0; i < subQueryColumns.size(); i++ ) {
subQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
subQueryColumns.get( i )
)
@ -4828,7 +4826,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
subQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
expression
)
@ -7441,7 +7438,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final JdbcLiteral<Integer> jdbcLiteral = new JdbcLiteral<>( 1, basicType( Integer.class ) );
subQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl( 1, 0, jdbcLiteral )
new SqlSelectionImpl( 0, jdbcLiteral )
);
return new ExistsPredicate( subQuerySpec, !predicate.isNegated(), getBooleanType() );

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.query.sqm.sql.internal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@ -109,6 +110,7 @@ public class SqlAstQueryPartProcessingStateImpl
// SqlExpressionResolver
private Map<?, ?> sqlSelectionMap;
private int nextJdbcPosition = 1;
@Override
public SqlSelection resolveSqlSelection(
@ -128,29 +130,21 @@ public class SqlAstQueryPartProcessingStateImpl
-1,
nestingFetchParent.getReferencedMappingType().getSelectableIndex( selectableName ),
javaType,
true,
typeConfiguration
);
}
final Map<Expression, SqlSelection> selectionMap;
final Map<Expression, Object> selectionMap;
if ( deduplicateSelectionItems ) {
final SqlSelection existing;
if ( sqlSelectionMap == null ) {
sqlSelectionMap = new HashMap<>();
existing = null;
}
else {
existing = (SqlSelection) sqlSelectionMap.get( expression );
}
if ( existing != null ) {
return existing;
}
//noinspection unchecked
selectionMap = (Map<Expression, SqlSelection>) sqlSelectionMap;
selectionMap = (Map<Expression, Object>) sqlSelectionMap;
}
else if ( fetchParent != null ) {
// De-duplicate selection items within the root of a fetch parent
final Map<FetchParent, Map<Expression, SqlSelection>> fetchParentSqlSelectionMap;
final Map<FetchParent, Map<Expression, Object>> fetchParentSqlSelectionMap;
final FetchParent root = fetchParent.getRoot();
if ( sqlSelectionMap == null ) {
sqlSelectionMap = fetchParentSqlSelectionMap = new HashMap<>();
@ -158,8 +152,8 @@ public class SqlAstQueryPartProcessingStateImpl
}
else {
//noinspection unchecked
fetchParentSqlSelectionMap = (Map<FetchParent, Map<Expression, SqlSelection>>) sqlSelectionMap;
final Map<Expression, SqlSelection> map = fetchParentSqlSelectionMap.get( root );
fetchParentSqlSelectionMap = (Map<FetchParent, Map<Expression, Object>>) sqlSelectionMap;
final Map<Expression, Object> map = fetchParentSqlSelectionMap.get( root );
if ( map == null ) {
fetchParentSqlSelectionMap.put( root, selectionMap = new HashMap<>() );
}
@ -167,31 +161,60 @@ public class SqlAstQueryPartProcessingStateImpl
selectionMap = map;
}
}
final SqlSelection sqlSelection = selectionMap.get( expression );
if ( sqlSelection != null ) {
return sqlSelection;
}
}
else {
selectionMap = null;
}
final int jdbcPosition;
final Object existingSelection;
if ( selectionMap != null ) {
existingSelection = selectionMap.get( expression );
if ( existingSelection != null ) {
if ( existingSelection instanceof SqlSelection ) {
final SqlSelection sqlSelection = (SqlSelection) existingSelection;
if ( sqlSelection.getExpressionType() == expression.getExpressionType() ) {
return sqlSelection;
}
jdbcPosition = sqlSelection.getJdbcResultSetIndex();
}
else {
final SqlSelection[] selections = (SqlSelection[]) existingSelection;
for ( SqlSelection sqlSelection : selections ) {
if ( sqlSelection.getExpressionType() == expression.getExpressionType() ) {
return sqlSelection;
}
}
jdbcPosition = selections[0].getJdbcResultSetIndex();
}
}
else {
jdbcPosition = nextJdbcPosition++;
}
}
else {
jdbcPosition = nextJdbcPosition++;
existingSelection = null;
}
final boolean virtual = existingSelection != null;
final SelectClause selectClause = ( (QuerySpec) queryPart ).getSelectClause();
final int valuesArrayPosition = selectClause.getSqlSelections().size();
final SqlSelection sqlSelection;
if ( isTopLevel() ) {
sqlSelection = expression.createDomainResultSqlSelection(
valuesArrayPosition + 1,
jdbcPosition,
valuesArrayPosition,
javaType,
virtual,
typeConfiguration
);
}
else {
sqlSelection = expression.createSqlSelection(
valuesArrayPosition + 1,
jdbcPosition,
valuesArrayPosition,
javaType,
virtual,
typeConfiguration
);
}
@ -199,7 +222,23 @@ public class SqlAstQueryPartProcessingStateImpl
selectClause.addSqlSelection( sqlSelection );
if ( selectionMap != null ) {
selectionMap.put( expression, sqlSelection );
if ( virtual ) {
final SqlSelection[] selections;
if ( existingSelection instanceof SqlSelection ) {
selections = new SqlSelection[2];
selections[0] = (SqlSelection) existingSelection;
}
else {
final SqlSelection[] existingSelections = (SqlSelection[]) existingSelection;
selections = new SqlSelection[existingSelections.length + 1];
System.arraycopy( existingSelections, 0, selections, 0, existingSelections.length );
}
selections[selections.length - 1] = sqlSelection;
selectionMap.put( expression, selections );
}
else {
selectionMap.put( expression, sqlSelection );
}
}
return sqlSelection;

View File

@ -2916,7 +2916,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
for ( int i = 0; i < sqlSelectionsSize; i++ ) {
syntheticSelectClause.addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
new ColumnReference(
queryGroupAlias,
@ -4590,6 +4589,9 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
int offset = 0;
for ( int i = 0; i < size; i++ ) {
final SqlSelection sqlSelection = sqlSelections.get( i );
if ( sqlSelection.isVirtual() ) {
continue;
}
if ( selectItemsToInline != null && selectItemsToInline.get( i ) ) {
parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS;
}
@ -4640,6 +4642,9 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
String separator = NO_SEPARATOR;
for ( int i = 0; i < size; i++ ) {
final SqlSelection sqlSelection = sqlSelections.get( i );
if ( sqlSelection.isVirtual() ) {
continue;
}
appendSql( separator );
if ( selectItemsToInline != null && selectItemsToInline.get( i ) ) {
parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS;
@ -5331,7 +5336,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
columnNames.add( "sort_col_" + i );
sqlSelections.add(
new SqlSelectionImpl(
sqlSelections.size() + 1,
sqlSelections.size(),
sortSpecification.getSortExpression()
)
@ -5645,7 +5649,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
for ( ColumnReference columnReference : columnReferences ) {
lhsReferencesQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
columnReference
)
@ -5695,7 +5698,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
final QuerySpec existsQuery = new QuerySpec( false, 1 );
existsQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new QueryLiteral<>( 1, getIntegerType() )
)
@ -5748,7 +5750,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
existsQuery.setHavingClauseRestrictions( querySpec.getHavingClauseRestrictions() );
existsQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new QueryLiteral<>( 1, getIntegerType() )
)
@ -5785,7 +5786,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
countQuery.setHavingClauseRestrictions( querySpec.getHavingClauseRestrictions() );
countQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
0,
new SelfRenderingAggregateFunctionSqlAstExpression(
"count",

View File

@ -8,12 +8,14 @@ package org.hibernate.sql.ast.spi;
import java.util.function.Function;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SelectablePath;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.type.NullType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;
@ -42,41 +44,42 @@ public interface SqlExpressionResolver {
*
* @see #resolveSqlExpression
*/
static ColumnReferenceKey createColumnReferenceKey(String tableExpression, String columnExpression) {
return new ColumnReferenceKey(tableExpression, new SelectablePath( columnExpression ) );
static ColumnReferenceKey createColumnReferenceKey(String tableExpression, String columnExpression, JdbcMapping jdbcMapping) {
return createColumnReferenceKey( tableExpression, new SelectablePath( columnExpression ), jdbcMapping );
}
/**
* Helper for generating an expression key for a column reference.
*
* @see #resolveSqlExpression
*/
static ColumnReferenceKey createColumnReferenceKey(TableReference tableReference, String columnExpression) {
return createColumnReferenceKey( tableReference, new SelectablePath( columnExpression ) );
static ColumnReferenceKey createColumnReferenceKey(TableReference tableReference, String columnExpression, JdbcMapping jdbcMapping) {
return createColumnReferenceKey( tableReference, new SelectablePath( columnExpression ), jdbcMapping );
}
static ColumnReferenceKey createColumnReferenceKey(TableReference tableReference, SelectablePath selectablePath) {
static ColumnReferenceKey createColumnReferenceKey(TableReference tableReference, SelectablePath selectablePath, JdbcMapping jdbcMapping) {
assert tableReference != null : "tableReference expected to be non-null";
assert selectablePath != null : "selectablePath expected to be non-null";
assert tableReference.getIdentificationVariable() != null : "tableReference#identificationVariable expected to be non-null";
final String qualifier = tableReference.getIdentificationVariable();
return createColumnReferenceKey( qualifier, selectablePath );
return createColumnReferenceKey( qualifier, selectablePath, jdbcMapping );
}
static ColumnReferenceKey createColumnReferenceKey(String qualifier, SelectablePath selectablePath) {
static ColumnReferenceKey createColumnReferenceKey(String qualifier, SelectablePath selectablePath, JdbcMapping jdbcMapping) {
assert qualifier != null : "qualifier expected to be non-null";
assert selectablePath != null : "selectablePath expected to be non-null";
return new ColumnReferenceKey( qualifier, selectablePath );
assert jdbcMapping != null : "jdbcMapping expected to be non-null";
return new ColumnReferenceKey( qualifier, selectablePath, jdbcMapping );
}
static ColumnReferenceKey createColumnReferenceKey(String columnExpression) {
assert columnExpression != null : "columnExpression expected to be non-null";
return new ColumnReferenceKey( "", new SelectablePath( columnExpression ) );
return createColumnReferenceKey( "", new SelectablePath( columnExpression ), NullType.INSTANCE );
}
/**
* Convenience form for creating a key from table expression and SelectableMapping
*/
static ColumnReferenceKey createColumnReferenceKey(String tableExpression, SelectableMapping selectable) {
return createColumnReferenceKey( tableExpression, selectable.getSelectablePath() );
return createColumnReferenceKey( tableExpression, selectable.getSelectablePath(), selectable.getJdbcMapping() );
}
/**
@ -85,7 +88,7 @@ public interface SqlExpressionResolver {
static ColumnReferenceKey createColumnReferenceKey(TableReference tableReference, SelectableMapping selectable) {
assert tableReference.containsAffectedTableName( selectable.getContainingTableExpression() )
: String.format( ROOT, "Expecting tables to match between TableReference (%s) and SelectableMapping (%s)", tableReference.getTableId(), selectable.getContainingTableExpression() );
return createColumnReferenceKey( tableReference, selectable.getSelectablePath() );
return createColumnReferenceKey( tableReference, selectable.getSelectablePath(), selectable.getJdbcMapping() );
}
default Expression resolveSqlExpression(TableReference tableReference, SelectableMapping selectableMapping) {
@ -117,10 +120,12 @@ public interface SqlExpressionResolver {
final class ColumnReferenceKey {
private final String tableQualifier;
private final SelectablePath selectablePath;
private final JdbcMapping jdbcMapping;
public ColumnReferenceKey(String tableQualifier, SelectablePath selectablePath) {
public ColumnReferenceKey(String tableQualifier, SelectablePath selectablePath, JdbcMapping jdbcMapping) {
this.tableQualifier = tableQualifier;
this.selectablePath = selectablePath;
this.jdbcMapping = jdbcMapping;
}
@Override
@ -132,18 +137,17 @@ public interface SqlExpressionResolver {
return false;
}
ColumnReferenceKey that = (ColumnReferenceKey) o;
if ( !tableQualifier.equals( that.tableQualifier ) ) {
return false;
}
return selectablePath.equals( that.selectablePath );
final ColumnReferenceKey that = (ColumnReferenceKey) o;
return tableQualifier.equals( that.tableQualifier )
&& selectablePath.equals( that.selectablePath )
&& jdbcMapping.equals( that.jdbcMapping );
}
@Override
public int hashCode() {
int result = tableQualifier.hashCode();
result = 31 * result + selectablePath.hashCode();
result = 31 * result + jdbcMapping.hashCode();
return result;
}
}

View File

@ -56,6 +56,12 @@ public interface SqlSelection extends SqlAstNode {
*/
JdbcMappingContainer getExpressionType();
/**
* Whether this is a virtual or a real selection item.
* Virtual selection items are not rendered into the SQL select clause.
*/
boolean isVirtual();
void accept(SqlAstWalker sqlAstWalker);
SqlSelection resolve(JdbcValuesMetadata jdbcResultsMetadata, SessionFactoryImplementor sessionFactory);

View File

@ -21,10 +21,28 @@ public interface SqlSelectionProducer {
* @param valuesArrayPosition The position in our {@linkplain RowProcessingState#getJdbcValue(SqlSelection) "current JDBC values array"}
* @param javaType The descriptor for the Java type to read the value as
* @param typeConfiguration The associated TypeConfiguration
* @deprecated Use {@link #createSqlSelection(int, int, JavaType, boolean, TypeConfiguration)} instead
*/
@Deprecated(forRemoval = true)
SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
TypeConfiguration typeConfiguration);
/**
* Create a SqlSelection for the given JDBC ResultSet position
*
* @param jdbcPosition The index position used to read values from JDBC
* @param valuesArrayPosition The position in our {@linkplain RowProcessingState#getJdbcValue(SqlSelection) "current JDBC values array"}
* @param javaType The descriptor for the Java type to read the value as
* @param virtual Whether the select is virtual or real. See {@link SqlSelection#isVirtual()}
* @param typeConfiguration The associated TypeConfiguration
*/
SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
boolean virtual,
TypeConfiguration typeConfiguration);
}

View File

@ -39,14 +39,41 @@ public interface Expression extends SqlAstNode, SqlSelectionProducer {
jdbcPosition,
valuesArrayPosition,
javaType,
this
this,
false
);
}
@Override
default SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
boolean virtual,
TypeConfiguration typeConfiguration) {
return new SqlSelectionImpl(
jdbcPosition,
valuesArrayPosition,
javaType,
this,
virtual
);
}
@Deprecated(forRemoval = true)
default SqlSelection createDomainResultSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
TypeConfiguration typeConfiguration) {
return createDomainResultSqlSelection( jdbcPosition, valuesArrayPosition, javaType, false, typeConfiguration );
}
default SqlSelection createDomainResultSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
boolean virtual,
TypeConfiguration typeConfiguration) {
// Apply possible jdbc type wrapping
final Expression expression;
@ -58,7 +85,7 @@ public interface Expression extends SqlAstNode, SqlSelectionProducer {
expression = expressionType.getJdbcMapping( 0 ).getJdbcType().wrapTopLevelSelectionExpression( this );
}
return expression == this
? createSqlSelection( jdbcPosition, valuesArrayPosition, javaType, typeConfiguration )
: new SqlSelectionImpl( jdbcPosition, valuesArrayPosition, expression );
? createSqlSelection( jdbcPosition, valuesArrayPosition, javaType, virtual, typeConfiguration )
: new SqlSelectionImpl( jdbcPosition, valuesArrayPosition, expression, virtual );
}
}

View File

@ -58,6 +58,22 @@ public abstract class DelegatingTableGroup implements TableGroup {
);
}
@Override
public SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaType javaType,
boolean virtual,
TypeConfiguration typeConfiguration) {
return getTableGroup().createSqlSelection(
jdbcPosition,
valuesArrayPosition,
javaType,
virtual,
typeConfiguration
);
}
@Override
public TableReference getTableReference(
NavigablePath navigablePath,

View File

@ -71,7 +71,8 @@ public abstract class AbstractJdbcParameter
jdbcPosition,
valuesArrayPosition,
javaType,
this
this,
false
);
}

View File

@ -22,12 +22,20 @@ public class ResolvedSqlSelection extends SqlSelectionImpl {
private final BasicType<Object> resolvedType;
public ResolvedSqlSelection(
int valuesArrayPosition,
Expression sqlExpression,
BasicType<Object> resolvedType) {
super( valuesArrayPosition + 1, valuesArrayPosition, null, sqlExpression, false );
this.resolvedType = resolvedType;
}
public ResolvedSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
Expression sqlExpression,
BasicType<Object> resolvedType) {
super( jdbcPosition, valuesArrayPosition, null, sqlExpression );
super( jdbcPosition, valuesArrayPosition, null, sqlExpression, false );
this.resolvedType = resolvedType;
}
@ -41,6 +49,11 @@ public class ResolvedSqlSelection extends SqlSelectionImpl {
return resolvedType;
}
@Override
public boolean isVirtual() {
return false;
}
@Override
public SqlSelection resolve(JdbcValuesMetadata jdbcResultsMetadata, SessionFactoryImplementor sessionFactory) {
return this;

View File

@ -116,7 +116,7 @@ public class RowProcessingStateStandardImpl extends BaseExecutionContext impleme
@Override
public Object getJdbcValue(int position) {
return jdbcValues.getCurrentRowValuesArray()[ position ];
return jdbcValues.getCurrentRowValue( position );
}
@Override
@ -130,6 +130,7 @@ public class RowProcessingStateStandardImpl extends BaseExecutionContext impleme
@Override
public void finishRowProcessing() {
jdbcValues.finishRowProcessing( this );
}
@Override

View File

@ -46,16 +46,31 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
private final int valuesArrayPosition;
private final Expression sqlExpression;
private final JavaType<?> jdbcJavaType;
private final boolean virtual;
public SqlSelectionImpl(int jdbcPosition, int valuesArrayPosition, Expression sqlExpression) {
this( jdbcPosition, valuesArrayPosition, null, sqlExpression );
public SqlSelectionImpl(Expression sqlExpression) {
this( 0, -1, null, sqlExpression, false );
}
public SqlSelectionImpl(int jdbcPosition, int valuesArrayPosition, JavaType<?> jdbcJavaType, Expression sqlExpression) {
public SqlSelectionImpl(int valuesArrayPosition, Expression sqlExpression) {
this( valuesArrayPosition + 1, valuesArrayPosition, null, sqlExpression, false );
}
public SqlSelectionImpl(int jdbcPosition, int valuesArrayPosition, Expression sqlExpression, boolean virtual) {
this( jdbcPosition, valuesArrayPosition, null, sqlExpression, virtual );
}
public SqlSelectionImpl(
int jdbcPosition,
int valuesArrayPosition,
JavaType<?> jdbcJavaType,
Expression sqlExpression,
boolean virtual) {
this.jdbcPosition = jdbcPosition;
this.valuesArrayPosition = valuesArrayPosition;
this.jdbcJavaType = jdbcJavaType;
this.sqlExpression = sqlExpression;
this.virtual = virtual;
}
@Override
@ -87,6 +102,11 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
return getExpression().getExpressionType();
}
@Override
public boolean isVirtual() {
return virtual;
}
@Override
public Expression getSqlExpression() {
return sqlExpression;
@ -126,11 +146,12 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
final SqlSelection that = (SqlSelection) o;
return jdbcPosition == that.getJdbcResultSetIndex() &&
valuesArrayPosition == that.getValuesArrayPosition() &&
Objects.equals( sqlExpression, that.getExpression() );
Objects.equals( sqlExpression, that.getExpression() ) &&
virtual == that.isVirtual();
}
@Override
public int hashCode() {
return Objects.hash( jdbcPosition, valuesArrayPosition, sqlExpression );
return Objects.hash( jdbcPosition, valuesArrayPosition, sqlExpression, virtual );
}
}

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.sql.results.jdbc.internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.sql.results.caching.QueryCachePutManager;
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -15,22 +13,10 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
* @author Steve Ebersole
*/
public abstract class AbstractJdbcValues implements JdbcValues {
private final QueryCachePutManager queryCachePutManager;
public AbstractJdbcValues(QueryCachePutManager queryCachePutManager) {
if ( queryCachePutManager == null ) {
throw new IllegalArgumentException( "QueryCachePutManager cannot be null" );
}
this.queryCachePutManager = queryCachePutManager;
}
@Override
public final boolean next(RowProcessingState rowProcessingState) {
final boolean hadRow = processNext( rowProcessingState );
if ( hadRow ) {
queryCachePutManager.registerJdbcRow( getCurrentRowValuesArray() );
}
return hadRow;
return processNext( rowProcessingState );
}
protected abstract boolean processNext(RowProcessingState rowProcessingState);
@ -64,12 +50,4 @@ public abstract class AbstractJdbcValues implements JdbcValues {
}
protected abstract boolean processPosition(int position, RowProcessingState rowProcessingState);
@Override
public final void finishUp(SharedSessionContractImplementor session) {
queryCachePutManager.finishUp( session );
release();
}
protected abstract void release();
}

View File

@ -8,9 +8,9 @@ package org.hibernate.sql.results.jdbc.internal;
import java.util.List;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.sql.results.ResultsLogger;
import org.hibernate.sql.results.caching.internal.QueryCachePutManagerDisabledImpl;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -29,12 +29,6 @@ public class JdbcValuesCacheHit extends AbstractJdbcValues {
private int position = -1;
public JdbcValuesCacheHit(Object[][] cachedData, JdbcValuesMapping resolvedMapping) {
// if we have a cache hit we should not be writing back to the cache.
// its silly because the state would always be the same.
//
// well actually, there are times when we want to write values back to the cache even though we had a hit...
// the case is related to the domain-data cache
super( QueryCachePutManagerDisabledImpl.INSTANCE );
this.cachedData = cachedData;
this.numberOfRows = cachedData.length;
this.resolvedMapping = resolvedMapping;
@ -237,7 +231,19 @@ public class JdbcValuesCacheHit extends AbstractJdbcValues {
}
@Override
protected void release() {
public Object getCurrentRowValue(int valueIndex) {
if ( position >= numberOfRows ) {
return null;
}
return cachedData[position][valueIndex];
}
@Override
public void finishRowProcessing(RowProcessingState rowProcessingState) {
}
@Override
public void finishUp(SharedSessionContractImplementor session) {
cachedData = null;
}

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.results.jdbc.internal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.BitSet;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.cache.spi.QueryResultsCache;
@ -32,11 +33,14 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
*/
public class JdbcValuesResultSetImpl extends AbstractJdbcValues {
private final QueryCachePutManager queryCachePutManager;
private final ResultSetAccess resultSetAccess;
private final JdbcValuesMapping valuesMapping;
private final ExecutionContext executionContext;
private final SqlSelection[] sqlSelections;
private final SqlSelection[] eagerSqlSelections;
private final BitSet initializedIndexes;
private final Object[] currentRowJdbcValues;
public JdbcValuesResultSetImpl(
@ -47,15 +51,61 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues {
JdbcValuesMapping valuesMapping,
JdbcValuesMetadata metadataForCache,
ExecutionContext executionContext) {
super( resolveQueryCachePutManager( executionContext, queryOptions, queryCacheKey, queryIdentifier, metadataForCache ) );
this.queryCachePutManager = resolveQueryCachePutManager(
executionContext,
queryOptions,
queryCacheKey,
queryIdentifier,
metadataForCache
);
this.resultSetAccess = resultSetAccess;
this.valuesMapping = valuesMapping;
this.executionContext = executionContext;
this.sqlSelections = valuesMapping.getSqlSelections().toArray( new SqlSelection[0] );
this.eagerSqlSelections = extractEagerSqlSelections( sqlSelections );
this.initializedIndexes = new BitSet( valuesMapping.getRowSize() );
this.currentRowJdbcValues = new Object[ valuesMapping.getRowSize() ];
}
/**
* Determine the selections which are eager i.e. safe to always extract.
* If a virtual selection exists, we must extract the value for that JDBC position lazily.
*/
private SqlSelection[] extractEagerSqlSelections(SqlSelection[] sqlSelections) {
BitSet lazyValuesPositions = null;
for ( int i = 0; i < sqlSelections.length; i++ ) {
final SqlSelection sqlSelection = sqlSelections[i];
if ( sqlSelection.isVirtual() ) {
if ( lazyValuesPositions == null ) {
lazyValuesPositions = new BitSet();
}
lazyValuesPositions.set( sqlSelection.getValuesArrayPosition() );
// Find the one preceding selection that refers to the same JDBC position
// and treat that as virtual to do lazy extraction
for ( int j = 0; j < i; j++ ) {
if ( sqlSelections[j].getJdbcResultSetIndex() == sqlSelection.getJdbcResultSetIndex() ) {
// There can only be a single selection which also has to be non-virtual
assert !sqlSelections[j].isVirtual();
lazyValuesPositions.set( sqlSelections[j].getValuesArrayPosition() );
break;
}
}
}
}
if ( lazyValuesPositions == null ) {
return sqlSelections;
}
final SqlSelection[] eagerSqlSelections = new SqlSelection[sqlSelections.length - lazyValuesPositions.cardinality()];
int i = 0;
for ( SqlSelection sqlSelection : sqlSelections ) {
if ( !lazyValuesPositions.get( sqlSelection.getValuesArrayPosition() ) ) {
eagerSqlSelections[i++] = sqlSelection;
}
}
return eagerSqlSelections;
}
private static QueryCachePutManager resolveQueryCachePutManager(
ExecutionContext executionContext,
QueryOptions queryOptions,
@ -257,7 +307,9 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues {
private void readCurrentRowValues() {
final ResultSet resultSet = resultSetAccess.getResultSet();
final SharedSessionContractImplementor session = executionContext.getSession();
for ( final SqlSelection sqlSelection : sqlSelections ) {
initializedIndexes.clear();
for ( final SqlSelection sqlSelection : eagerSqlSelections ) {
initializedIndexes.set( sqlSelection.getValuesArrayPosition() );
try {
currentRowJdbcValues[ sqlSelection.getValuesArrayPosition() ] = sqlSelection.getJdbcValueExtractor().extract(
resultSet,
@ -276,7 +328,8 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues {
}
@Override
protected void release() {
public final void finishUp(SharedSessionContractImplementor session) {
queryCachePutManager.finishUp( session );
resultSetAccess.release();
}
@ -290,6 +343,34 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues {
return currentRowJdbcValues;
}
@Override
public void finishRowProcessing(RowProcessingState rowProcessingState) {
queryCachePutManager.registerJdbcRow( currentRowJdbcValues );
}
@Override
public Object getCurrentRowValue(int valueIndex) {
if ( !initializedIndexes.get( valueIndex ) ) {
initializedIndexes.set( valueIndex );
final SqlSelection sqlSelection = sqlSelections[valueIndex];
try {
currentRowJdbcValues[valueIndex] = sqlSelection.getJdbcValueExtractor().extract(
resultSetAccess.getResultSet(),
sqlSelection.getJdbcResultSetIndex(),
executionContext.getSession()
);
}
catch ( SQLException e ) {
// do not want to wrap in ExecutionException here
throw executionContext.getSession().getJdbcServices().getSqlExceptionHelper().convert(
e,
"Could not extract column [" + sqlSelection.getJdbcResultSetIndex() + "] from JDBC ResultSet"
);
}
}
return currentRowJdbcValues[valueIndex];
}
@Override
public void setFetchSize(int fetchSize) {
try {

View File

@ -21,7 +21,7 @@ public interface JdbcValues {
/**
* Advances the "cursor position" and returns a boolean indicating whether
* there is a row available to read via {@link #getCurrentRowValuesArray()}.
* there is a row available to read via {@link #getCurrentRowValue(int)}.
*
* @return {@code true} if there are results
*/
@ -29,7 +29,7 @@ public interface JdbcValues {
/**
* Advances the "cursor position" in reverse and returns a boolean indicating whether
* there is a row available to read via {@link #getCurrentRowValuesArray()}.
* there is a row available to read via {@link #getCurrentRowValue(int)}.
*
* @return {@code true} if there are results available
*/
@ -37,7 +37,7 @@ public interface JdbcValues {
/**
* Advances the "cursor position" the indicated number of rows and returns a boolean
* indicating whether there is a row available to read via {@link #getCurrentRowValuesArray()}.
* indicating whether there is a row available to read via {@link #getCurrentRowValue(int)}.
*
* @param numberOfRows The number of rows to advance. This can also be negative meaning to
* move in reverse
@ -74,6 +74,17 @@ public interface JdbcValues {
*/
Object[] getCurrentRowValuesArray();
/**
* Get the JDBC value at the given index for the row currently positioned at within
* this source.
*
* @return The current row's JDBC values, or {@code null} if the position
* is beyond the end of the available results.
*/
Object getCurrentRowValue(int valueIndex);
void finishRowProcessing(RowProcessingState rowProcessingState);
/**
* Give implementations a chance to finish processing
*/

View File

@ -0,0 +1,170 @@
/*
* 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.mapping.basic;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.type.SqlTypes;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
/**
* @author Christian Beikov
*/
@DomainModel(annotatedClasses = {
PolymorphicJsonTests.EntityWithJson.class,
PolymorphicJsonTests.EntityWithJsonA.class,
PolymorphicJsonTests.EntityWithJsonB.class
})
@SessionFactory
public abstract class PolymorphicJsonTests {
@ServiceRegistry(settings = @Setting(name = AvailableSettings.JSON_FORMAT_MAPPER, value = "jsonb"))
public static class JsonB extends PolymorphicJsonTests {
public JsonB() {
}
}
@ServiceRegistry(settings = @Setting(name = AvailableSettings.JSON_FORMAT_MAPPER, value = "jackson"))
public static class Jackson extends PolymorphicJsonTests {
public Jackson() {
}
}
@BeforeEach
public void setup(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
session.persist( new EntityWithJsonA( 1, new PropertyA( "e1" ) ) );
session.persist( new EntityWithJsonB( 2, new PropertyB( 123 ) ) );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
session.remove( session.find( EntityWithJson.class, 1 ) );
session.remove( session.find( EntityWithJson.class, 2 ) );
}
);
}
@Test
public void verifyReadWorks(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
EntityWithJson entityWithJsonA = session.find( EntityWithJson.class, 1 );
EntityWithJson entityWithJsonB = session.find( EntityWithJson.class, 2 );
assertThat( entityWithJsonA, instanceOf( EntityWithJsonA.class ) );
assertThat( entityWithJsonB, instanceOf( EntityWithJsonB.class ) );
assertThat( ( (EntityWithJsonA) entityWithJsonA ).property.value, is( "e1" ) );
assertThat( ( (EntityWithJsonB) entityWithJsonB ).property.value, is( 123 ) );
}
);
}
@Entity(name = "EntityWithJson")
@Table(name = "EntityWithJson")
public static abstract class EntityWithJson {
@Id
private Integer id;
public EntityWithJson() {
}
public EntityWithJson(Integer id) {
this.id = id;
}
}
@Entity(name = "EntityWithJsonA")
public static class EntityWithJsonA extends EntityWithJson {
@JdbcTypeCode( SqlTypes.JSON )
private PropertyA property;
public EntityWithJsonA() {
}
public EntityWithJsonA(Integer id, PropertyA property) {
super( id );
this.property = property;
}
}
@Entity(name = "EntityWithJsonB")
public static class EntityWithJsonB extends EntityWithJson {
@JdbcTypeCode( SqlTypes.JSON )
private PropertyB property;
public EntityWithJsonB() {
}
public EntityWithJsonB(Integer id, PropertyB property) {
super( id );
this.property = property;
}
}
public static class PropertyA {
private String value;
public PropertyA() {
}
public PropertyA(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class PropertyB {
private int value;
public PropertyB() {
}
public PropertyB(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}