Skip to content

Commit

Permalink
Various improvements:
Browse files Browse the repository at this point in the history
* Sprinkle some @nullable annotations to better understand nullness guarantees
* Fix some potential NPEs
* Improve Oracle array_agg emulation
* Prepare for aggregate component array support
  • Loading branch information
beikov committed May 3, 2024
1 parent 75e1f17 commit 940c898
Show file tree
Hide file tree
Showing 41 changed files with 208 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.hibernate.query.sqm.produce.function.FunctionArgumentException;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
Expand All @@ -44,6 +45,8 @@
import org.hibernate.type.descriptor.jdbc.ObjectJdbcType;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

import static org.hibernate.query.sqm.produce.function.FunctionParameterType.NUMERIC;

/**
Expand Down Expand Up @@ -240,7 +243,7 @@ public BasicValuedMapping resolveFunctionReturnType(
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
final SqmExpressible<?> expressible = arguments.get( 0 ).getExpressible();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@
import java.util.function.Supplier;

import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicTypeReference;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* Simplified API allowing users to contribute
* {@link org.hibernate.query.sqm.function.SqmFunctionDescriptor}s
Expand All @@ -42,15 +44,7 @@ public StandardSQLFunction(String name, boolean useParentheses, BasicTypeReferen
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
return resolveFunctionReturnType( impliedType, null, arguments, typeConfiguration );
}

@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
return type == null ? null : typeConfiguration.getBasicTypeRegistry().resolve( type );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicType;
Expand All @@ -21,6 +22,8 @@
import java.util.List;
import java.util.function.Supplier;

import org.checkerframework.checker.nullness.qual.Nullable;

import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.extractArgumentType;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping;
import static org.hibernate.type.SqlTypes.*;
Expand Down Expand Up @@ -59,15 +62,7 @@ public SumReturnTypeResolver(TypeConfiguration typeConfiguration) {
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
return resolveFunctionReturnType( impliedType, null, arguments, typeConfiguration );
}

@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
if ( impliedType != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.sql.ast.SqlAstTranslator;
Expand All @@ -35,6 +36,7 @@
import org.hibernate.type.spi.TypeConfiguration;

import jakarta.persistence.TemporalType;
import org.checkerframework.checker.nullness.qual.Nullable;

import static java.util.Arrays.asList;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
Expand Down Expand Up @@ -129,15 +131,7 @@ public TimestampdiffFunctionReturnTypeResolver(BasicType<Long> longType, BasicTy
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
return resolveFunctionReturnType( impliedType, null, arguments, typeConfiguration );
}

@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
final BasicType<?> invariantType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* A {@link FunctionReturnTypeResolver} that resolves the array type based on an argument.
* The inferred type and implied type have precedence though.
Expand All @@ -37,10 +40,12 @@ public ArrayViaArgumentReturnTypeResolver(int arrayIndex) {
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
final MappingModelExpressible<?> inferredType = inferredTypeSupplier.get();
final MappingModelExpressible<?> inferredType = converter == null
? null
: converter.resolveFunctionImpliedReturnType();
if ( inferredType != null ) {
if ( inferredType instanceof ReturnableType<?> ) {
return (ReturnableType<?>) inferredType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* A {@link FunctionReturnTypeResolver} that resolves an array type based on the arguments,
* which are supposed to be of the element type. The inferred type and implied type have precedence though.
Expand All @@ -41,10 +44,12 @@ private ArrayViaElementArgumentReturnTypeResolver(boolean list, int elementIndex
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
final MappingModelExpressible<?> inferredType = inferredTypeSupplier.get();
final MappingModelExpressible<?> inferredType = converter == null
? null
: converter.resolveFunctionImpliedReturnType();
if ( inferredType != null ) {
if ( inferredType instanceof ReturnableType<?> ) {
return (ReturnableType<?>) inferredType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* A {@link FunctionReturnTypeResolver} that resolves the array element type based on an argument.
* The inferred type and implied type have precedence though.
Expand All @@ -37,10 +40,12 @@ private ElementViaArrayArgumentReturnTypeResolver(int arrayIndex) {
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
final MappingModelExpressible<?> inferredType = inferredTypeSupplier.get();
final MappingModelExpressible<?> inferredType = converter == null
? null
: converter.resolveFunctionImpliedReturnType();
if ( inferredType != null ) {
if ( inferredType instanceof ReturnableType<?> ) {
return (ReturnableType<?>) inferredType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ protected boolean finishInitialization(
containingTableExpression = rootTableExpression;
columnExpression = rootTableKeyColumnNames[ columnPosition ];
}
final NavigableRole role = navigableRole.append( bootPropertyDescriptor.getName() );
final SelectablePath selectablePath;
final String columnDefinition;
final Long length;
Expand Down Expand Up @@ -310,18 +311,18 @@ protected boolean finishInitialization(

attributeMapping = MappingModelCreationHelper.buildBasicAttributeMapping(
bootPropertyDescriptor.getName(),
navigableRole.append( bootPropertyDescriptor.getName() ),
role,
attributeIndex,
attributeIndex,
bootPropertyDescriptor,
declarer,
(BasicType<?>) subtype,
basicValue.getResolution().getLegacyResolvedBasicType(),
containingTableExpression,
columnExpression,
selectablePath,
selectable.isFormula(),
selectable.getCustomReadExpression(),
selectable.getWriteExpr( ( (BasicType<?>) subtype ).getJdbcMapping(), dialect ),
selectable.getWriteExpr( basicValue.getResolution().getJdbcMapping(), dialect ),
columnDefinition,
length,
precision,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5702,6 +5702,7 @@ protected AttributeMapping generateNonIdAttributeMapping(
}

if ( attrType instanceof BasicType ) {
final NavigableRole role = getNavigableRole().append( bootProperty.getName() );
final String attrColumnExpression;
final boolean isAttrColumnExpressionFormula;
final String customReadExpr;
Expand Down Expand Up @@ -5774,12 +5775,12 @@ protected AttributeMapping generateNonIdAttributeMapping(

return MappingModelCreationHelper.buildBasicAttributeMapping(
attrName,
getNavigableRole().append( bootProperty.getName() ),
role,
stateArrayPosition,
fetchableIndex,
bootProperty,
this,
(BasicType<?>) attrType,
(BasicType<?>) value.getType(),
tableExpression,
attrColumnExpression,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package org.hibernate.query.criteria;

import jakarta.persistence.TupleElement;
import org.checkerframework.checker.nullness.qual.Nullable;

import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
Expand All @@ -17,10 +18,10 @@
* @author Steve Ebersole
*/
public interface JpaTupleElement<T> extends TupleElement<T>, JpaCriteriaNode {
JavaType<T> getJavaTypeDescriptor();
@Nullable JavaType<T> getJavaTypeDescriptor();

@Override
default Class<? extends T> getJavaType() {
default @Nullable Class<? extends T> getJavaType() {
// todo (6.0) : can this signature just return `Class<T>`?
return getJavaTypeDescriptor() == null ? null : getJavaTypeDescriptor().getJavaTypeClass();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* Representation of a function call in the SQL AST for impls that know how to
* render themselves.
Expand All @@ -44,8 +46,8 @@ public class SelfRenderingFunctionSqlAstExpression
private final String functionName;
private final FunctionRenderer renderer;
private final List<? extends SqlAstNode> sqlAstArguments;
private final ReturnableType<?> type;
private final JdbcMappingContainer expressible;
private final @Nullable ReturnableType<?> type;
private final @Nullable JdbcMappingContainer expressible;

/**
* @deprecated Use {@link #SelfRenderingFunctionSqlAstExpression(String, FunctionRenderer, List, ReturnableType, JdbcMappingContainer)} instead
Expand All @@ -55,8 +57,8 @@ public SelfRenderingFunctionSqlAstExpression(
String functionName,
FunctionRenderingSupport renderer,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> type,
JdbcMappingContainer expressible) {
@Nullable ReturnableType<?> type,
@Nullable JdbcMappingContainer expressible) {
this.functionName = functionName;
this.renderer = renderer::render;
this.sqlAstArguments = sqlAstArguments;
Expand All @@ -69,8 +71,8 @@ public SelfRenderingFunctionSqlAstExpression(
String functionName,
FunctionRenderer renderer,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> type,
JdbcMappingContainer expressible) {
@Nullable ReturnableType<?> type,
@Nullable JdbcMappingContainer expressible) {
this.functionName = functionName;
this.renderer = renderer;
this.sqlAstArguments = sqlAstArguments;
Expand Down Expand Up @@ -108,7 +110,7 @@ protected FunctionRenderer getFunctionRenderer() {
return renderer;
}

protected ReturnableType<?> getType() {
protected @Nullable ReturnableType<?> getType() {
return type;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

import org.hibernate.query.sqm.tree.expression.SqmParameter;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* @author Marco Belladelli
*/
public class NoParamSqmCopyContext extends SimpleSqmCopyContext {
@Override
public <T> T getCopy(T original) {
public <T> @Nullable T getCopy(T original) {
if ( original instanceof SqmParameter<?> ) {
return original;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import org.hibernate.query.sqm.tree.SqmCopyContext;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* @author Marco Belladelli
*/
Expand All @@ -18,7 +20,7 @@ public class SimpleSqmCopyContext implements SqmCopyContext {

@Override
@SuppressWarnings( "unchecked" )
public <T> T getCopy(T original) {
public <T> @Nullable T getCopy(T original) {
return (T) map.get( original );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,12 @@ private static EntityPersister getEntityDescriptor(SessionFactoryImplementor fac
* @see TypecheckUtil#assertAssignable(String, SqmPath, SqmTypedNode, SessionFactoryImplementor)
*/
public static void assertComparable(Expression<?> x, Expression<?> y, SessionFactoryImplementor factory) {
SqmExpression<?> left = (SqmExpression<?>) x;
SqmExpression<?> right = (SqmExpression<?>) y;
if ( left.getTupleLength() != null && right.getTupleLength() != null
&& left.getTupleLength().intValue() != right.getTupleLength().intValue() ) {
final SqmExpression<?> left = (SqmExpression<?>) x;
final SqmExpression<?> right = (SqmExpression<?>) y;
final Integer leftTupleLength = left.getTupleLength();
final Integer rightTupleLength;
if ( leftTupleLength != null && ( rightTupleLength = right.getTupleLength() ) != null
&& leftTupleLength.intValue() != rightTupleLength.intValue() ) {
throw new SemanticException( "Cannot compare tuples of different lengths" );
}

Expand Down
Loading

0 comments on commit 940c898

Please sign in to comment.