initial working literal and parameter selection
This commit is contained in:
parent
5631a702a7
commit
26b08fd35e
|
@ -44,11 +44,13 @@ import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||||
import org.hibernate.query.spi.SelectQueryPlan;
|
import org.hibernate.query.spi.SelectQueryPlan;
|
||||||
|
import org.hibernate.query.sqm.SqmExpressable;
|
||||||
import org.hibernate.query.sqm.mutation.spi.DeleteHandler;
|
import org.hibernate.query.sqm.mutation.spi.DeleteHandler;
|
||||||
import org.hibernate.query.sqm.mutation.spi.UpdateHandler;
|
import org.hibernate.query.sqm.mutation.spi.UpdateHandler;
|
||||||
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
||||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||||
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelection;
|
import org.hibernate.query.sqm.tree.select.SqmSelection;
|
||||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||||
|
@ -199,11 +201,32 @@ public class QuerySqmImpl<R>
|
||||||
|
|
||||||
final SqmSelection sqmSelection = selections.get( 0 );
|
final SqmSelection sqmSelection = selections.get( 0 );
|
||||||
|
|
||||||
if ( ! resultClass.isAssignableFrom( sqmSelection.getNodeType().getExpressableJavaTypeDescriptor().getJavaType() ) ) {
|
if ( sqmSelection.getSelectableNode() instanceof SqmParameter ) {
|
||||||
|
final SqmParameter sqmParameter = (SqmParameter) sqmSelection.getSelectableNode();
|
||||||
|
|
||||||
|
// we may not yet know a selection type
|
||||||
|
if ( sqmParameter.getNodeType() == null || sqmParameter.getNodeType().getExpressableJavaTypeDescriptor() == null ) {
|
||||||
|
// we can't verify the result type up front
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyResultType( resultClass, sqmSelection.getNodeType(), sessionFactory );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void verifyResultType(
|
||||||
|
Class<T> resultClass,
|
||||||
|
SqmExpressable<?> sqmExpressable,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
assert sqmExpressable != null;
|
||||||
|
assert sqmExpressable.getExpressableJavaTypeDescriptor() != null;
|
||||||
|
|
||||||
|
if ( ! resultClass.isAssignableFrom( sqmExpressable.getExpressableJavaTypeDescriptor().getJavaType() ) ) {
|
||||||
final String errorMessage = String.format(
|
final String errorMessage = String.format(
|
||||||
"Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array",
|
"Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array",
|
||||||
resultClass.getName(),
|
resultClass.getName(),
|
||||||
sqmSelection.getNodeType().getExpressableJavaTypeDescriptor().getJavaType().getName()
|
sqmExpressable.getExpressableJavaTypeDescriptor().getJavaType().getName()
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) {
|
if ( sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) {
|
||||||
|
@ -214,7 +237,6 @@ public class QuerySqmImpl<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SessionFactoryImplementor getSessionFactory() {
|
public SessionFactoryImplementor getSessionFactory() {
|
||||||
|
|
|
@ -220,6 +220,16 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
return sqlAliasBaseManager;
|
return sqlAliasBaseManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomainParameterXref getDomainParameterXref() {
|
||||||
|
return domainParameterXref;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryParameterBindings getDomainParameterBindings() {
|
||||||
|
return domainParameterBindings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LockMode determineLockMode(String identificationVariable) {
|
public LockMode determineLockMode(String identificationVariable) {
|
||||||
return queryOptions.getLockOptions().getEffectiveLockMode( identificationVariable );
|
return queryOptions.getLockOptions().getEffectiveLockMode( identificationVariable );
|
||||||
|
@ -653,7 +663,17 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmExpression) {
|
protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmExpression) {
|
||||||
final SqmExpressable<?> nodeType = sqmExpression.getNodeType();
|
SqmExpressable<?> nodeType = sqmExpression.getNodeType();
|
||||||
|
|
||||||
|
if ( nodeType == null ) {
|
||||||
|
if ( sqmExpression instanceof SqmParameter ) {
|
||||||
|
final SqmParameter sqmParameter = (SqmParameter) sqmExpression;
|
||||||
|
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( domainParameterXref.getQueryParameter( sqmParameter ) );
|
||||||
|
assert binding != null;
|
||||||
|
|
||||||
|
nodeType = binding.getBindType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
|
MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.query.sqm.sql;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
|
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
|
@ -32,6 +34,10 @@ public interface SqlAstCreationState {
|
||||||
|
|
||||||
SqlAliasBaseGenerator getSqlAliasBaseGenerator();
|
SqlAliasBaseGenerator getSqlAliasBaseGenerator();
|
||||||
|
|
||||||
|
DomainParameterXref getDomainParameterXref();
|
||||||
|
|
||||||
|
QueryParameterBindings getDomainParameterBindings();
|
||||||
|
|
||||||
LockMode determineLockMode(String identificationVariable);
|
LockMode determineLockMode(String identificationVariable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,16 +9,24 @@ package org.hibernate.query.sqm.sql.internal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
|
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||||
|
import org.hibernate.query.SemanticException;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||||
|
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmParameterInterpretation implements Expression {
|
public class SqmParameterInterpretation implements Expression, DomainResultProducer {
|
||||||
private final SqmParameter sqmParameter;
|
private final SqmParameter sqmParameter;
|
||||||
private final MappingModelExpressable valueMapping;
|
private final MappingModelExpressable valueMapping;
|
||||||
|
|
||||||
|
@ -48,4 +56,40 @@ public class SqmParameterInterpretation implements Expression {
|
||||||
public MappingModelExpressable getExpressionType() {
|
public MappingModelExpressable getExpressionType() {
|
||||||
return valueMapping;
|
return valueMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomainResult createDomainResult(
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
if ( resolvedExpression instanceof SqlTuple ) {
|
||||||
|
throw new SemanticException( "Composite query parameter cannot be used in select" );
|
||||||
|
}
|
||||||
|
|
||||||
|
AllowableParameterType nodeType = sqmParameter.getNodeType();
|
||||||
|
if ( nodeType == null ) {
|
||||||
|
final QueryParameterImplementor<?> queryParameter = creationState.getSqlAstCreationState()
|
||||||
|
.getDomainParameterXref()
|
||||||
|
.getQueryParameter( sqmParameter );
|
||||||
|
final QueryParameterBinding<?> binding = creationState.getSqlAstCreationState()
|
||||||
|
.getDomainParameterBindings()
|
||||||
|
.getBinding( queryParameter );
|
||||||
|
nodeType = binding.getBindType();
|
||||||
|
}
|
||||||
|
|
||||||
|
final SqlSelection sqlSelection = creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||||
|
resolvedExpression,
|
||||||
|
nodeType.getExpressableJavaTypeDescriptor(),
|
||||||
|
creationState.getSqlAstCreationState()
|
||||||
|
.getCreationContext()
|
||||||
|
.getSessionFactory()
|
||||||
|
.getTypeConfiguration()
|
||||||
|
);
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
return new BasicResult(
|
||||||
|
sqlSelection.getValuesArrayPosition(),
|
||||||
|
resultVariable,
|
||||||
|
nodeType.getExpressableJavaTypeDescriptor()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ public abstract class AbstractLiteral<T>
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return new BasicResult<>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getJdbcResultSetIndex(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
type.getMappedTypeDescriptor().getMappedJavaTypeDescriptor()
|
type.getMappedTypeDescriptor().getMappedJavaTypeDescriptor()
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,13 +13,16 @@ import java.util.function.Consumer;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
|
import org.hibernate.metamodel.mapping.SqlExpressable;
|
||||||
import org.hibernate.sql.ast.Clause;
|
import org.hibernate.sql.ast.Clause;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.exec.ExecutionException;
|
import org.hibernate.sql.exec.ExecutionException;
|
||||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
|
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
@ -28,7 +31,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJdbcParameter
|
public abstract class AbstractJdbcParameter
|
||||||
implements JdbcParameter, JdbcParameterBinder, MappingModelExpressable {
|
implements JdbcParameter, JdbcParameterBinder, MappingModelExpressable, SqlExpressable {
|
||||||
|
|
||||||
private final JdbcMapping jdbcMapping;
|
private final JdbcMapping jdbcMapping;
|
||||||
|
|
||||||
|
@ -41,6 +44,29 @@ public abstract class AbstractJdbcParameter
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JdbcMapping getJdbcMapping() {
|
||||||
|
return jdbcMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlSelection createSqlSelection(
|
||||||
|
int jdbcPosition,
|
||||||
|
int valuesArrayPosition,
|
||||||
|
JavaTypeDescriptor javaTypeDescriptor,
|
||||||
|
TypeConfiguration typeConfiguration) {
|
||||||
|
// todo (6.0) : investigate "virtual" or "static" selections
|
||||||
|
// - anything that is the same for each row always - parameter, literal, etc;
|
||||||
|
// the idea would be to write the value directly into the JdbcValues array
|
||||||
|
// and not generating a SQL selection in the query sent to DB
|
||||||
|
return new SqlSelectionImpl(
|
||||||
|
jdbcPosition,
|
||||||
|
valuesArrayPosition,
|
||||||
|
this,
|
||||||
|
jdbcMapping
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bindParameterValue(
|
public void bindParameterValue(
|
||||||
PreparedStatement statement,
|
PreparedStatement statement,
|
||||||
|
|
|
@ -160,6 +160,28 @@ public class SmokeTests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHqlSelectLiteral(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final QueryImplementor<String> query = session.createQuery( "select 'items' from SimpleEntity e", String.class );
|
||||||
|
final String attribute1 = query.uniqueResult();
|
||||||
|
assertThat( attribute1, is( "items" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHqlSelectParameter(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final QueryImplementor<String> query = session.createQuery( "select :param from SimpleEntity e", String.class );
|
||||||
|
final String attribute1 = query.setParameter( "param", "items" ).uniqueResult();
|
||||||
|
assertThat( attribute1, is( "items" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Dynamic instantiations
|
// Dynamic instantiations
|
||||||
|
@ -254,6 +276,26 @@ public class SmokeTests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHqlNestedDynamicInstantiationWithLiteral(SessionFactoryScope scope) {
|
||||||
|
scope.getSessionFactory().inTransaction(
|
||||||
|
session -> {
|
||||||
|
final Query<CategorizedListItemDto> query = session.createQuery(
|
||||||
|
"select new CategorizedListItemDto( new ListItemDto( 'items', e.component.attribute1 ), e.component.attribute2, e.name ) from SimpleEntity e",
|
||||||
|
CategorizedListItemDto.class
|
||||||
|
);
|
||||||
|
|
||||||
|
final CategorizedListItemDto dto = query.getSingleResult();
|
||||||
|
assertThat( dto, notNullValue() );
|
||||||
|
assertThat( dto.category, notNullValue() );
|
||||||
|
assertThat( dto.category.code, is( "items") );
|
||||||
|
assertThat( dto.category.value, is( "a1") );
|
||||||
|
assertThat( dto.code, is( "a2" ) );
|
||||||
|
assertThat( dto.value, is( "Fab" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHqlMultipleDynamicInstantiation(SessionFactoryScope scope) {
|
public void testHqlMultipleDynamicInstantiation(SessionFactoryScope scope) {
|
||||||
scope.getSessionFactory().inTransaction(
|
scope.getSessionFactory().inTransaction(
|
||||||
|
@ -278,7 +320,7 @@ public class SmokeTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBasicSetterDynamicInstantiation(SessionFactoryScope scope) {
|
public void testHqlBasicSetterDynamicInstantiation(SessionFactoryScope scope) {
|
||||||
scope.getSessionFactory().inTransaction(
|
scope.getSessionFactory().inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
final Query<BasicSetterBasedDto> query = session.createQuery(
|
final Query<BasicSetterBasedDto> query = session.createQuery(
|
||||||
|
|
Loading…
Reference in New Issue