Add the Object type to the basic type registry and resolve it by Java type instead of referring to JavaObjectType or StandardBasicTypes.OBJECT_TYPE

Also add special JdbcTypeDescriptor implementations that resolve the parameter type or use a VARBINARY on null values, as needed for some dialects, which register these descriptors
This commit is contained in:
Christian Beikov 2021-09-29 18:47:15 +02:00
parent 05f643f208
commit 10e508dfe7
23 changed files with 409 additions and 167 deletions

View File

@ -792,52 +792,57 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
protected <T> QueryImplementor<T> buildNamedQuery(String queryName, Class<T> resultType) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
try {
pulseTransactionCoordinator();
delayedAfterCompletion();
// this method can be called for either a named HQL query or a named native query
// this method can be called for either a named HQL query or a named native query
// first see if it is a named HQL query
final NamedHqlQueryMemento namedHqlDescriptor = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getHqlQueryMemento( queryName );
// first see if it is a named HQL query
final NamedHqlQueryMemento namedHqlDescriptor = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getHqlQueryMemento( queryName );
if ( namedHqlDescriptor != null ) {
HqlQueryImplementor<T> query = namedHqlDescriptor.toQuery( this, resultType );
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic HQL query" );
if ( namedHqlDescriptor != null ) {
HqlQueryImplementor<T> query = namedHqlDescriptor.toQuery( this, resultType );
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic HQL query" );
}
applyQuerySettingsAndHints( query );
if ( namedHqlDescriptor.getLockOptions() != null ) {
query.setLockOptions( namedHqlDescriptor.getLockOptions() );
}
return query;
}
applyQuerySettingsAndHints( query );
if ( namedHqlDescriptor.getLockOptions() != null ) {
query.setLockOptions( namedHqlDescriptor.getLockOptions() );
// otherwise, see if it is a named native query
final NamedNativeQueryMemento namedNativeDescriptor = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
final NativeQueryImplementor<T> query;
if ( resultType == null) {
query = namedNativeDescriptor.toQuery( this );
}
else {
query = namedNativeDescriptor.toQuery( this, resultType );
}
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native SQL query" );
}
applyQuerySettingsAndHints( query );
return query;
}
return query;
// todo (6.0) : allow this for named stored procedures as well?
// ultimately they are treated as a Query
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + queryName + "]" ) );
}
// otherwise, see if it is a named native query
final NamedNativeQueryMemento namedNativeDescriptor = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
final NativeQueryImplementor<T> query;
if ( resultType == null) {
query = namedNativeDescriptor.toQuery( this );
}
else {
query = namedNativeDescriptor.toQuery( this, resultType );
}
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native SQL query" );
}
applyQuerySettingsAndHints( query );
return query;
catch (RuntimeException e) {
throw !( e instanceof IllegalArgumentException ) ? new IllegalArgumentException( e ) : e;
}
// todo (6.0) : allow this for named stored procedures as well?
// ultimately they are treated as a Query
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + queryName + "]" ) );
}
protected void applyQuerySettingsAndHints(Query query) {

View File

@ -26,8 +26,7 @@ import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
@ -37,11 +36,14 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping, SelectableMap
private final String rowIdName;
private final EntityMappingType declaringType;
private final String tableExpression;
private final BasicType<Object> rowIdType;
public EntityRowIdMappingImpl(String rowIdName, String tableExpression, EntityMappingType declaringType) {
this.rowIdName = rowIdName;
this.tableExpression = tableExpression;
this.declaringType = declaringType;
this.rowIdType = declaringType.getEntityPersister().getFactory().getTypeConfiguration()
.getBasicTypeForJavaType( Object.class );
}
@Override
@ -51,12 +53,12 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping, SelectableMap
@Override
public MappingType getPartMappingType() {
return this::getJavaTypeDescriptor;
return rowIdType;
}
@Override
public JavaTypeDescriptor<?> getJavaTypeDescriptor() {
return JavaObjectType.INSTANCE.getJavaTypeDescriptor();
return rowIdType.getJavaTypeDescriptor();
}
@Override
@ -98,18 +100,18 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping, SelectableMap
// having to write a Dialect
null,
null,
JavaObjectType.INSTANCE,
rowIdType,
sqlAstCreationState.getCreationContext().getSessionFactory()
)
),
JavaObjectType.INSTANCE.getJdbcMapping().getJavaTypeDescriptor(),
rowIdType.getJavaTypeDescriptor(),
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
);
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
resultVariable,
getJavaTypeDescriptor(),
rowIdType.getJavaTypeDescriptor(),
navigablePath
);
}
@ -121,7 +123,7 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping, SelectableMap
@Override
public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
action.accept( offset, JavaObjectType.INSTANCE );
action.accept( offset, getJdbcMapping() );
return getJdbcTypeCount();
}
@ -170,6 +172,6 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping, SelectableMap
@Override
public JdbcMapping getJdbcMapping() {
return StandardBasicTypes.INTEGER;
return rowIdType.getJdbcMapping();
}
}

View File

@ -180,6 +180,7 @@ import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -3037,7 +3038,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
}
private <J> BasicDomainType<J> resolveExpressableTypeBasic(Class<J> javaType) {
private <J> BasicType<J> resolveExpressableTypeBasic(Class<J> javaType) {
return creationContext.getJpaMetamodel().getTypeConfiguration().standardBasicTypeForJavaType( javaType );
}
@ -3093,7 +3094,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
functionName,
true,
null,
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.OBJECT_TYPE )
StandardFunctionReturnTypeResolvers.invariant(
resolveExpressableTypeBasic( Object.class )
)
);
}
return functionTemplate.generateSqmExpression(
@ -3137,7 +3140,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
functionName,
true,
null,
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.OBJECT_TYPE ),
StandardFunctionReturnTypeResolvers.invariant(
resolveExpressableTypeBasic( Object.class )
),
functionName,
filterExpression != null ? FunctionKind.AGGREGATE : FunctionKind.NORMAL,
null,

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.query.internal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import jakarta.persistence.TemporalType;
@ -19,7 +18,7 @@ import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
import org.hibernate.query.spi.QueryParameterBindingValidator;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.NullType;
import org.hibernate.type.descriptor.java.CoercionException;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -101,7 +100,7 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
}
@Override
public void setBindValue(T value) {
public void setBindValue(T value, boolean resolveJdbcTypeIfNecessary) {
if ( handleAsMultiValue( value ) ) {
return;
}
@ -119,6 +118,10 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
validate( value );
}
if ( resolveJdbcTypeIfNecessary && bindType == null && value == null ) {
//noinspection unchecked
bindType = (AllowableParameterType<T>) NullType.INSTANCE;
}
bindValue( value );
}
@ -148,9 +151,11 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
this.isBound = true;
this.bindValue = value;
if ( bindType == null && value != null ) {
//noinspection unchecked
this.bindType = (AllowableParameterType) typeResolver.resolveParameterBindType( value );
if ( bindType == null ) {
if ( value != null ) {
//noinspection unchecked
this.bindType = (AllowableParameterType<T>) typeResolver.resolveParameterBindType( value );
}
}
}

View File

@ -752,6 +752,10 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// QueryParameter handling
protected boolean resolveJdbcParameterTypeIfNecessary() {
return true;
}
@Override
@SuppressWarnings( {"unchecked", "rawtypes"} )
public Set<Parameter<?>> getParameters() {
@ -943,7 +947,7 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
@Override
public <P> QueryImplementor<R> setParameter(QueryParameter<P> parameter, P value) {
locateBinding( parameter ).setBindValue( value );
locateBinding( parameter ).setBindValue( value, resolveJdbcParameterTypeIfNecessary() );
return this;
}
@ -953,7 +957,7 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
setParameter( parameter, ( (TypedParameterValue) value ).getValue(), ( (TypedParameterValue) value ).getType() );
}
else {
locateBinding( parameter ).setBindValue( value );
locateBinding( parameter ).setBindValue( value, resolveJdbcParameterTypeIfNecessary() );
}
return this;
@ -986,7 +990,7 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
setParameterList( name, (Collection) value );
}
else {
locateBinding( name ).setBindValue( value );
locateBinding( name ).setBindValue( value, resolveJdbcParameterTypeIfNecessary() );
}
return this;
@ -1003,7 +1007,7 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
setParameterList( position, (Collection<?>) value );
}
else {
locateBinding( position ).setBindValue( value );
locateBinding( position ).setBindValue( value, resolveJdbcParameterTypeIfNecessary() );
}
return this;
}

View File

@ -50,7 +50,15 @@ public interface QueryParameterBinding<T> {
/**
* Sets the parameter binding value. The inherent parameter type (if known) is assumed
*/
void setBindValue(T value);
default void setBindValue(T value) {
setBindValue( value, false );
}
/**
* Sets the parameter binding value. The inherent parameter type (if known) is assumed.
* The flag controls whether the parameter type should be resolved if necessary.
*/
void setBindValue(T value, boolean resolveJdbcTypeIfNecessary);
/**
* Sets the parameter binding value using the explicit Type.

View File

@ -11,49 +11,25 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.action.internal.BulkOperationCleanupAction;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelHelper;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.spi.SqlOmittingQueryOptions;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.query.sqm.internal.SqmUtil;
import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.MutatingTableReferenceGroupWrapper;
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcDelete;
import org.hibernate.sql.exec.spi.JdbcMutation;
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
import org.hibernate.sql.exec.spi.NativeJdbcMutation;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
import org.hibernate.sql.results.spi.RowTransformer;
import org.hibernate.type.StandardBasicTypes;
/**
* @author Steve Ebersole
@ -96,7 +72,7 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
type = param.getHibernateType();
}
if ( type == null ) {
type = StandardBasicTypes.OBJECT_TYPE;
type = executionContext.getSession().getTypeConfiguration().getBasicTypeForJavaType( Object.class );
}
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();

View File

@ -35,7 +35,6 @@ import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.type.StandardBasicTypes;
/**
* @author Steve Ebersole
@ -92,7 +91,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
type = param.getHibernateType();
}
if ( type == null ) {
type = StandardBasicTypes.OBJECT_TYPE;
type = executionContext.getSession().getTypeConfiguration().getBasicTypeForJavaType( Object.class );
}
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
@ -157,7 +156,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
type = param.getHibernateType();
}
if ( type == null ) {
type = StandardBasicTypes.OBJECT_TYPE;
type = executionContext.getSession().getTypeConfiguration().getBasicTypeForJavaType( Object.class );
}
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();

View File

@ -505,6 +505,12 @@ public class QuerySqmImpl<R>
return parameters;
}
@Override
protected boolean resolveJdbcParameterTypeIfNecessary() {
// No need to resolve JDBC parameter types as we know them from the SQM model
return false;
}
@Override
public LockModeType getLockMode() {
if ( ! isSelectQuery() ) {

View File

@ -258,7 +258,6 @@ import org.hibernate.sql.ast.tree.expression.ExtractUnit;
import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
@ -313,7 +312,6 @@ 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.StandardBasicTypes;
import org.hibernate.type.VersionType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
@ -1732,7 +1730,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
selection.getValuesArrayPosition(),
new QueryLiteral<>(
selection.getValuesArrayPosition(),
StandardBasicTypes.INTEGER
basicType( Integer.class )
)
)
)
@ -2657,8 +2655,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
private Expression createCaseExpression(SqmPath<?> lhs, EntityDomainType<?> treatTarget, Expression expression) {
@SuppressWarnings("rawtypes")
final MappingModelExpressable mappingModelExpressable = (MappingModelExpressable) expression.getExpressionType();
final BasicValuedMapping mappingModelExpressable = (BasicValuedMapping) expression.getExpressionType();
final List<CaseSearchedExpression.WhenFragment> whenFragments = new ArrayList<>( 1 );
whenFragments.add(
new CaseSearchedExpression.WhenFragment(
@ -2669,7 +2666,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return new CaseSearchedExpression(
mappingModelExpressable,
whenFragments,
new NullnessLiteral( mappingModelExpressable )
new QueryLiteral<>( null, mappingModelExpressable )
);
}
@ -2702,18 +2699,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final Supplier<MappingModelExpressable> inferableTypeAccess = inferrableTypeAccessStack.getCurrent();
if ( literal instanceof SqmLiteralNull ) {
MappingModelExpressable mappingModelExpressable = inferableTypeAccess.get();
MappingModelExpressable<?> mappingModelExpressable = inferableTypeAccess.get();
if ( mappingModelExpressable == null ) {
mappingModelExpressable = determineCurrentExpressable( literal );
}
if ( mappingModelExpressable instanceof BasicValuedMapping ) {
return new NullnessLiteral( mappingModelExpressable );
return new QueryLiteral<>( null, (BasicValuedMapping) mappingModelExpressable );
}
final MappingModelExpressable keyExpressable = getKeyExpressable( mappingModelExpressable );
final MappingModelExpressable<?> keyExpressable = getKeyExpressable( mappingModelExpressable );
if ( keyExpressable == null ) {
// todo (6.0): this should be fine, right?
return new NullnessLiteral( JavaObjectType.INSTANCE );
// throw new IllegalArgumentException( "Could not determine type for null literal" );
// Default to the Object type
return new QueryLiteral<>( null, basicType( Object.class ) );
}
final List<Expression> expressions = new ArrayList<>( keyExpressable.getJdbcTypeCount() );
@ -2729,11 +2725,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return new SqlTuple( expressions, mappingModelExpressable );
}
final MappingModelExpressable inferableExpressable = inferableTypeAccess.get();
final MappingModelExpressable<?> inferableExpressable = inferableTypeAccess.get();
if ( inferableExpressable instanceof ConvertibleModelPart ) {
final ConvertibleModelPart convertibleModelPart = (ConvertibleModelPart) inferableExpressable;
final BasicValueConverter valueConverter = convertibleModelPart.getValueConverter();
final BasicValueConverter<Object, Object> valueConverter = convertibleModelPart.getValueConverter();
if ( valueConverter != null ) {
final Object literalValue = literal.getLiteralValue();
@ -2770,7 +2766,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
.getEntityDescriptor( (Class<?>) literalValue );
}
else {
final JavaTypeDescriptor javaTypeDescriptor = discriminatorMapping.getJdbcMapping().getJavaTypeDescriptor();
final JavaTypeDescriptor<?> javaTypeDescriptor = discriminatorMapping.getJdbcMapping().getJavaTypeDescriptor();
final Object discriminatorValue;
if ( javaTypeDescriptor.getJavaTypeClass().isInstance( literalValue ) ) {
discriminatorValue = literalValue;
@ -2793,8 +2789,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return new EntityTypeLiteral( mappingDescriptor );
}
final MappingModelExpressable expressable;
final MappingModelExpressable localExpressable = SqmMappingModelHelper.resolveMappingModelExpressable(
final MappingModelExpressable<?> expressable;
final MappingModelExpressable<?> localExpressable = SqmMappingModelHelper.resolveMappingModelExpressable(
literal,
getCreationContext().getDomainModel(),
getFromClauseAccess()::findTableGroup
@ -2803,7 +2799,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
expressable = getElementExpressable( inferableExpressable );
}
else {
final MappingModelExpressable elementExpressable = getElementExpressable( localExpressable );
final MappingModelExpressable<?> elementExpressable = getElementExpressable( localExpressable );
if ( elementExpressable instanceof BasicType<?> ) {
expressable = InferredBasicValueResolver.resolveSqlTypeIndicators(
this,
@ -3177,10 +3173,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
if ( parameterSqmType == null || parameterSqmType == StandardBasicTypes.OBJECT_TYPE ) {
assert binding.getBindValue() == null;
// todo (6.0): this should be fine, right?
return StandardBasicTypes.OBJECT_TYPE;
if ( parameterSqmType == null ) {
// Default to the Object type
return basicType( Object.class );
}
else if ( parameterSqmType instanceof MappingModelExpressable<?> && parameterSqmType.getJavaType() == Object.class ) {
return (MappingModelExpressable<?>) parameterSqmType;
}
if ( parameterSqmType instanceof SqmPath ) {
@ -4086,7 +4084,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
private <J> BasicValuedMapping basicType(Class<J> javaType) {
private <J> BasicType<J> basicType(Class<J> javaType) {
return creationContext.getDomainModel().getTypeConfiguration().getBasicTypeForJavaType( javaType );
}
@ -4928,7 +4926,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final int jdbcTypeCount = collectionKeyDescriptor.getJdbcTypeCount();
assert jdbcTypeCount > 0;
final JdbcLiteral<Integer> jdbcLiteral = new JdbcLiteral<>( 1, StandardBasicTypes.INTEGER );
final JdbcLiteral<Integer> jdbcLiteral = new JdbcLiteral<>( 1, basicType( Integer.class ) );
subQuerySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl( 1, 0, jdbcLiteral )
);

View File

@ -45,8 +45,7 @@ public class LiteralHelper {
}
public static SqmLiteral<Integer> integerLiteral(int value, QueryEngine queryEngine) {
//noinspection unchecked
return new SqmLiteral(
return new SqmLiteral<>(
value,
StandardBasicTypes.INTEGER,
queryEngine.getCriteriaBuilder()

View File

@ -30,9 +30,15 @@ public class SqmLiteral<T>
public SqmLiteral(T value, SqmExpressable<T> inherentType, NodeBuilder nodeBuilder) {
super( inherentType, nodeBuilder );
assert value != null;
this.value = value;
}
protected SqmLiteral(SqmExpressable<T> inherentType, NodeBuilder nodeBuilder) {
super( inherentType, nodeBuilder );
this.value = null;
}
public T getLiteralValue() {
return value;
}

View File

@ -14,15 +14,16 @@ import org.hibernate.query.sqm.SemanticQueryWalker;
* @author Steve Ebersole
*/
public class SqmLiteralNull<T> extends SqmLiteral<T> {
private static final SqmExpressable<Object> NULL_TYPE = () -> null;
public SqmLiteralNull(NodeBuilder nodeBuilder) {
//noinspection unchecked
this( NULL_TYPE, nodeBuilder );
this( (SqmExpressable<T>) NULL_TYPE, nodeBuilder );
}
public SqmLiteralNull(
SqmExpressable<T> expressableType,
NodeBuilder nodeBuilder) {
super( null, expressableType, nodeBuilder );
public SqmLiteralNull(SqmExpressable<T> expressableType, NodeBuilder nodeBuilder) {
super( expressableType, nodeBuilder );
}
@Override
@ -35,8 +36,6 @@ public class SqmLiteralNull<T> extends SqmLiteral<T> {
return "<literal-null>";
}
private static SqmExpressable NULL_TYPE = () -> null;
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "null" );

View File

@ -11,7 +11,6 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.type.StandardBasicTypes;
/**
* Base support for {@link JpaTupleElement} impls
@ -32,18 +31,6 @@ public abstract class AbstractJpaTupleElement<T>
setExpressableType( expressableType );
}
@SuppressWarnings("unused")
protected AbstractJpaTupleElement(Class<T> javaType, NodeBuilder criteriaBuilder) {
super( criteriaBuilder );
if ( javaType != null ) {
setJavaType( javaType );
}
else {
setExpressableType( StandardBasicTypes.OBJECT_TYPE );
}
}
@Override
public String getAlias() {
return alias;
@ -65,20 +52,4 @@ public abstract class AbstractJpaTupleElement<T>
this.expressableType = (SqmExpressable<T>) expressableType;
}
/**
* Protected access to set the JavaTypeDescriptor via Java Class
*/
protected void setJavaType(Class<T> targetType) {
if ( targetType != null ) {
setExpressableType(
nodeBuilder().getDomainModel()
.getTypeConfiguration()
.standardBasicTypeForJavaType( targetType )
);
}
else {
setExpressableType( StandardBasicTypes.OBJECT_TYPE );
}
}
}

View File

@ -83,8 +83,9 @@ public abstract class AbstractJdbcParameter
jdbcMapping = this.jdbcMapping;
}
if ( jdbcMapping == null ) {
jdbcMapping = guessBindType( executionContext, binding );
// If the parameter type is not known from the context i.e. null or Object, infer it from the bind value
if ( jdbcMapping == null || jdbcMapping.getMappedJavaTypeDescriptor().getJavaTypeClass() == Object.class ) {
jdbcMapping = guessBindType( executionContext, binding, jdbcMapping );
}
final Object bindValue = binding.getBindValue();
@ -98,12 +99,22 @@ public abstract class AbstractJdbcParameter
);
}
private JdbcMapping guessBindType(ExecutionContext executionContext, JdbcParameterBinding binding) {
private JdbcMapping guessBindType(ExecutionContext executionContext, JdbcParameterBinding binding, JdbcMapping jdbcMapping) {
final Class<?> valueClass;
if ( binding.getBindValue() == null ) {
if ( jdbcMapping != null ) {
return jdbcMapping;
}
valueClass = Object.class;
}
else {
valueClass = binding.getBindValue().getClass();
}
final BasicType<?> basicType = executionContext.getSession()
.getFactory()
.getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( binding.getBindValue().getClass() );
.getRegisteredType( valueClass );
return basicType.getJdbcMapping();
}

View File

@ -7,6 +7,8 @@
package org.hibernate.type;
import org.hibernate.type.descriptor.java.JavaObjectTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectJdbcTypeDescriptor;
/**
@ -22,8 +24,17 @@ public class JavaObjectType extends AbstractSingleColumnStandardBasicType<Object
super( ObjectJdbcTypeDescriptor.INSTANCE, JavaObjectTypeDescriptor.INSTANCE );
}
public JavaObjectType(JdbcTypeDescriptor jdbcTypeDescriptor, JavaTypeDescriptor<Object> javaTypeDescriptor) {
super( jdbcTypeDescriptor, javaTypeDescriptor );
}
@Override
public String getName() {
return "JAVA_OBJECT";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
}

View File

@ -0,0 +1,27 @@
/*
* 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.type;
import org.hibernate.type.descriptor.java.JavaObjectTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullResolvingJdbcTypeDescriptor;
/**
* @author Christian Beikov
*/
public class NullType extends JavaObjectType {
/**
* Singleton access
*/
public static final NullType INSTANCE = new NullType();
public NullType() {
super( ObjectNullResolvingJdbcTypeDescriptor.INSTANCE, JavaObjectTypeDescriptor.INSTANCE );
}
}

View File

@ -942,6 +942,13 @@ public final class StandardBasicTypes {
DbTimestampType.INSTANCE.getName()
);
handle(
OBJECT_TYPE,
null,
basicTypeRegistry,
"object", Object.class.getName()
);
// todo (6.0) - ? how to handle DbTimestampType?
// DbTimestampType was really just a variant of TimestampType with overridden
// version (opt lock) support

View File

@ -19,7 +19,8 @@ import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Descriptor for
* Descriptor for binding objects
*
* @author Steve Ebersole
*/
public class ObjectJdbcTypeDescriptor implements JdbcTypeDescriptor {
@ -72,25 +73,25 @@ public class ObjectJdbcTypeDescriptor implements JdbcTypeDescriptor {
@Override
@SuppressWarnings("unchecked")
public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) {
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor );
}
return new BasicExtractor( javaTypeDescriptor, this ) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected Object doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return rs.getObject( paramIndex );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return (X) rs.getObject( paramIndex );
}
@Override
protected Object doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return statement.getObject( index );
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return (X) statement.getObject( index );
}
@Override
protected Object doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return statement.getObject( name );
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return (X) statement.getObject( name );
}
};
}

View File

@ -0,0 +1,67 @@
/*
* 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.type.descriptor.jdbc;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Descriptor for binding objects, but binding nulls with Types.VARBINARY
*
* @author Christian Beikov
*/
public class ObjectNullAsBinaryTypeJdbcTypeDescriptor extends ObjectJdbcTypeDescriptor {
/**
* Singleton access
*/
public static final ObjectNullAsBinaryTypeJdbcTypeDescriptor INSTANCE = new ObjectNullAsBinaryTypeJdbcTypeDescriptor( Types.JAVA_OBJECT );
public ObjectNullAsBinaryTypeJdbcTypeDescriptor(int jdbcTypeCode) {
super( jdbcTypeCode );
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
}
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options)
throws SQLException {
st.setNull( index, Types.VARBINARY );
}
@Override
protected void doBindNull(CallableStatement st, String name, WrapperOptions options)
throws SQLException {
st.setNull( name, Types.VARBINARY );
}
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setObject( index, value, getJdbcTypeCode() );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, getJdbcTypeCode() );
}
};
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.type.descriptor.jdbc;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Descriptor for binding objects, but binding nulls with Types.NULL
*
* @author Christian Beikov
*/
public class ObjectNullAsNullTypeJdbcTypeDescriptor extends ObjectJdbcTypeDescriptor {
/**
* Singleton access
*/
public static final ObjectNullAsNullTypeJdbcTypeDescriptor INSTANCE = new ObjectNullAsNullTypeJdbcTypeDescriptor( Types.JAVA_OBJECT );
public ObjectNullAsNullTypeJdbcTypeDescriptor(int jdbcTypeCode) {
super( jdbcTypeCode );
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
}
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options)
throws SQLException {
st.setNull( index, Types.NULL );
}
@Override
protected void doBindNull(CallableStatement st, String name, WrapperOptions options)
throws SQLException {
st.setNull( name, Types.NULL );
}
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setObject( index, value, getJdbcTypeCode() );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, getJdbcTypeCode() );
}
};
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.type.descriptor.jdbc;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Descriptor for binding objects, but binding nulls with the resolved parameter type
*
* @author Christian Beikov
*/
public class ObjectNullResolvingJdbcTypeDescriptor extends ObjectJdbcTypeDescriptor {
/**
* Singleton access
*/
public static final ObjectNullResolvingJdbcTypeDescriptor INSTANCE = new ObjectNullResolvingJdbcTypeDescriptor( Types.JAVA_OBJECT );
public ObjectNullResolvingJdbcTypeDescriptor(int jdbcTypeCode) {
super( jdbcTypeCode );
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
}
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options)
throws SQLException {
st.setNull( index, st.getParameterMetaData().getParameterType( index ) );
}
@Override
protected void doBindNull(CallableStatement st, String name, WrapperOptions options)
throws SQLException {
st.setNull( name, Types.JAVA_OBJECT );
}
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setObject( index, value, getJdbcTypeCode() );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, getJdbcTypeCode() );
}
};
}
}

View File

@ -53,7 +53,6 @@ import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.SingleColumnType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -477,7 +476,9 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
final SqmExpressable<?>[] components = new SqmExpressable<?>[typedNodes.size()];
for ( int i = 0; i < typedNodes.size(); i++ ) {
final SqmExpressable<?> sqmExpressable = typedNodes.get( i ).getNodeType();
components[i] = sqmExpressable == null ? JavaObjectType.INSTANCE : sqmExpressable;
components[i] = sqmExpressable != null
? sqmExpressable
: getBasicTypeForJavaType( Object.class );
}
return arrayTuples.computeIfAbsent(
new ArrayCacheKey( components ),