fix NPE when selecting enum value
This commit is contained in:
parent
53d38262ba
commit
6f1ddc32dd
|
@ -82,6 +82,7 @@ import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
|
|||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
|
@ -91,15 +92,15 @@ import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPath;
|
|||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.DynamicInstantiationNature;
|
||||
import org.hibernate.query.FetchClauseType;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.QueryLogging;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
|
@ -150,12 +151,12 @@ import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedRootJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
|
@ -270,6 +271,7 @@ import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
|||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.Collation;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.Distinct;
|
||||
import org.hibernate.sql.ast.tree.expression.Duration;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -345,7 +347,11 @@ import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
|||
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.JavaObjectType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaType;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.UserVersionType;
|
||||
|
@ -5274,6 +5280,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return (Expression) sqmExpression.getDiscriminatorSource().accept( this );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"raw","unchecked"})
|
||||
@Override
|
||||
public Object visitEnumLiteral(SqmEnumLiteral<?> sqmEnumLiteral) {
|
||||
final BasicValuedMapping inferrableType = (BasicValuedMapping) inferrableTypeAccessStack.getCurrent().get();
|
||||
|
@ -5285,9 +5292,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return new QueryLiteral<>( jdbcValue, inferredPart );
|
||||
}
|
||||
|
||||
return new QueryLiteral<>(
|
||||
final EnumJavaTypeDescriptor<?> enumJtd = sqmEnumLiteral.getExpressableJavaTypeDescriptor();
|
||||
final JdbcType jdbcType = getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( SqlTypes.TINYINT );
|
||||
final BasicJavaType<Integer> relationalJtd = (BasicJavaType) getTypeConfiguration()
|
||||
.getJavaTypeDescriptorRegistry()
|
||||
.getDescriptor( Integer.class );
|
||||
final BasicType<?> jdbcMappingType = getTypeConfiguration().getBasicTypeRegistry().resolve( relationalJtd, jdbcType );
|
||||
|
||||
return new ConvertedQueryLiteral(
|
||||
sqmEnumLiteral.getEnumValue(),
|
||||
(BasicValuedMapping) determineValueMapping( sqmEnumLiteral )
|
||||
new OrdinalEnumValueConverter( enumJtd, jdbcType, relationalJtd ),
|
||||
jdbcMappingType
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
|||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.Collation;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.Distinct;
|
||||
import org.hibernate.sql.ast.tree.expression.Duration;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -157,6 +158,8 @@ public interface SqlAstWalker {
|
|||
|
||||
void visitQueryLiteral(QueryLiteral<?> queryLiteral);
|
||||
|
||||
void acceptConvertedQueryLiteral(ConvertedQueryLiteral<?,?> convertedQueryLiteral);
|
||||
|
||||
void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression);
|
||||
|
||||
void visitModifiedSubQueryExpression(ModifiedSubQueryExpression expression);
|
||||
|
|
|
@ -87,6 +87,7 @@ import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
|||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.Collation;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.Distinct;
|
||||
import org.hibernate.sql.ast.tree.expression.Duration;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -4556,6 +4557,11 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
visitLiteral( queryLiteral );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptConvertedQueryLiteral(ConvertedQueryLiteral<?, ?> convertedQueryLiteral) {
|
||||
visitLiteral( convertedQueryLiteral );
|
||||
}
|
||||
|
||||
private void visitLiteral(Literal literal) {
|
||||
if ( literal.getLiteralValue() == null ) {
|
||||
appendSql( SqlAppender.NULL_KEYWORD );
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
|||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.Collation;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.Distinct;
|
||||
import org.hibernate.sql.ast.tree.expression.Duration;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -469,6 +470,10 @@ public class AbstractSqlAstWalker implements SqlAstWalker {
|
|||
public void visitQueryLiteral(QueryLiteral<?> queryLiteral) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptConvertedQueryLiteral(ConvertedQueryLiteral<?,?> convertedQueryLiteral) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.sql.ast.tree.expression;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
* Mainly intended for cases where we have a converter for a literal,
|
||||
* but not a full ConvertibleModelPart.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ConvertedQueryLiteral<D,R> implements Literal, DomainResultProducer<D> {
|
||||
private final D domainLiteralValue;
|
||||
private final R relationalLiteralValue;
|
||||
private final BasicValueConverter<D,R> converter;
|
||||
private final BasicValuedMapping relationalMapping;
|
||||
|
||||
public ConvertedQueryLiteral(
|
||||
D domainLiteralValue,
|
||||
BasicValueConverter<D, R> converter,
|
||||
BasicValuedMapping relationalMapping) {
|
||||
this.domainLiteralValue = domainLiteralValue;
|
||||
this.converter = converter;
|
||||
this.relationalMapping = relationalMapping;
|
||||
this.relationalLiteralValue = converter.toRelationalValue( domainLiteralValue );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getLiteralValue() {
|
||||
return relationalLiteralValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return relationalMapping.getJdbcMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<D> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
|
||||
applySqlSelections( creationState );
|
||||
return new ConstantDomainResult<>( domainLiteralValue, converter.getDomainJavaDescriptor(), resultVariable );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySqlSelections(DomainResultCreationState creationState) {
|
||||
// if there is another DomainResultProducer that generates sql-selections,
|
||||
// we actually would not even need to generate this. we do not know that
|
||||
// here.
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
final SqlExpressionResolver expressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||
expressionResolver.resolveSqlSelection(
|
||||
this,
|
||||
relationalMapping.getExpressableJavaTypeDescriptor(),
|
||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindParameterValue(
|
||||
PreparedStatement statement,
|
||||
int startPosition,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
ExecutionContext executionContext) throws SQLException {
|
||||
//noinspection unchecked
|
||||
relationalMapping.getJdbcMapping().getJdbcValueBinder().bind(
|
||||
statement,
|
||||
relationalLiteralValue,
|
||||
startPosition,
|
||||
executionContext.getSession()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(SqlAstWalker sqlTreeWalker) {
|
||||
sqlTreeWalker.acceptConvertedQueryLiteral( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMappingContainer getExpressionType() {
|
||||
return relationalMapping.getJdbcMapping();
|
||||
}
|
||||
|
||||
|
||||
private static class ConstantDomainResult<D> implements DomainResult<D>, DomainResultAssembler<D> {
|
||||
private final D literal;
|
||||
private final JavaType<D> javaType;
|
||||
private final String resultAlias;
|
||||
|
||||
public ConstantDomainResult(D literal, JavaType<D> javaType, String resultAlias) {
|
||||
this.literal = literal;
|
||||
this.javaType = javaType;
|
||||
this.resultAlias = resultAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultVariable() {
|
||||
return resultAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<?> getResultJavaTypeDescriptor() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResultAssembler<D> createResultAssembler(FetchParentAccess parentAccess, AssemblerCreationState creationState) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public D assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
|
||||
return literal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<D> getAssembledJavaTypeDescriptor() {
|
||||
return javaType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ import java.sql.SQLException;
|
|||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.ConvertibleModelPart;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.animal.Classification;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
@ -23,8 +24,11 @@ import java.time.LocalDate;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaTypeDescriptor;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
@ -267,17 +271,46 @@ public class LiteralTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testEnums(SessionFactoryScope scope) {
|
||||
public void testEnumLiteralInPredicate(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from Zoo where classification=COOL" ).getResultList();
|
||||
session.createQuery( "from Zoo where classification=Classification.COOL" ).getResultList();
|
||||
session.createQuery( "from Zoo where classification=org.hibernate.testing.orm.domain.animal.Classification.COOL" ).getResultList();
|
||||
|
||||
assertThat( session.createQuery( "select org.hibernate.testing.orm.domain.animal.Classification.LAME" )
|
||||
.getSingleResult(), is( org.hibernate.testing.orm.domain.animal.Classification.LAME ) );
|
||||
assertThat( session.createQuery( "select org.hibernate.testing.orm.domain.gambit.EntityOfBasics$Gender.MALE" )
|
||||
.getSingleResult(), is( org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.MALE ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerLiteralInSelect(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat( session.createQuery( "select 1" ).getSingleResult(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumLiteralInSelect(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
{
|
||||
final QueryImplementor<Object[]> query = session.createQuery( "select 1, org.hibernate.testing.orm.domain.animal.Classification.LAME" );
|
||||
final Object[] result = query.getSingleResult();
|
||||
final Object classification = result[ 1 ];
|
||||
|
||||
Assertions.assertThat( classification ).isEqualTo( Classification.LAME );
|
||||
}
|
||||
|
||||
{
|
||||
final QueryImplementor<Classification> query = session.createQuery( "select org.hibernate.testing.orm.domain.animal.Classification.LAME" );
|
||||
final Classification result = query.getSingleResult();
|
||||
|
||||
Assertions.assertThat( result ).isEqualTo( Classification.LAME );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue