Treat PREFERRED_BOOLEAN_JDBC_TYPE_CODE value BIT like BOOLEAN and only consider the value in CastFunction

This commit is contained in:
Christian Beikov 2021-02-23 20:23:15 +01:00
parent fc3c20f669
commit 0fd5fe7d5e
5 changed files with 49 additions and 7 deletions

View File

@ -453,7 +453,13 @@ public abstract class Dialect implements ConversionContext {
//about but in certain cases it doesn't allow some useful typecasts,
//which must be emulated in a dialect-specific way
queryEngine.getSqmFunctionRegistry().register("cast", new CastFunction(this));
queryEngine.getSqmFunctionRegistry().register(
"cast",
new CastFunction(
this,
queryEngine.getPreferredSqlTypeCodeForBoolean()
)
);
//ANSI SQL extract() function is supported on the databases we care most
//about (though it is called datepart() in some of them) but HQL defines

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.dialect.function;
import java.sql.Types;
import java.util.List;
import org.hibernate.dialect.Dialect;
@ -27,32 +28,52 @@ import org.hibernate.sql.ast.tree.expression.Expression;
*/
public class CastFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
private Dialect dialect;
private final Dialect dialect;
private final CastType booleanCastType;
public CastFunction(Dialect dialect) {
public CastFunction(Dialect dialect, int preferredSqlTypeCodeForBoolean) {
super(
"cast",
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.useArgType( 2 )
);
this.dialect = dialect;
this.booleanCastType = getBooleanCastType( preferredSqlTypeCodeForBoolean );
}
private CastType getBooleanCastType(int preferredSqlTypeCodeForBoolean) {
switch ( preferredSqlTypeCodeForBoolean ) {
case Types.BIT:
case Types.SMALLINT:
case Types.TINYINT:
return CastType.INTEGER_BOOLEAN;
}
return CastType.BOOLEAN;
}
@Override
public void render(SqlAppender sqlAppender, List<SqlAstNode> arguments, SqlAstWalker walker) {
final Expression source = (Expression) arguments.get( 0 );
final JdbcMapping sourceMapping = ( (SqlExpressable) source.getExpressionType() ).getJdbcMapping();
final CastType sourceType = sourceMapping.getCastType();
final CastType sourceType = getCastType( sourceMapping );
final CastTarget castTarget = (CastTarget) arguments.get( 1 );
final JdbcMapping targetJdbcMapping = castTarget.getExpressionType().getJdbcMapping();
final CastType targetType = targetJdbcMapping.getCastType();
final CastType targetType = getCastType( targetJdbcMapping );
String cast = dialect.castPattern( sourceType, targetType );
new PatternRenderer( cast ).render( sqlAppender, arguments, walker );
}
private CastType getCastType(JdbcMapping sourceMapping) {
final CastType castType = sourceMapping.getCastType();
if ( castType == CastType.BOOLEAN ) {
return booleanCastType;
}
return castType;
}
// @Override
// protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
// List<SqmTypedNode<?>> arguments,

View File

@ -70,6 +70,7 @@ public class QueryEngine {
return new QueryEngine(
() -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(),
sessionFactory.getSessionFactoryOptions().getCriteriaValueHandlingMode(),
sessionFactory.getSessionFactoryOptions().getPreferredSqlTypeCodeForBoolean(),
metadata.buildNamedQueryRepository( sessionFactory ),
hqlTranslator,
sqmTranslatorFactory,
@ -88,10 +89,12 @@ public class QueryEngine {
private final NativeQueryInterpreter nativeQueryInterpreter;
private final QueryInterpretationCache interpretationCache;
private final SqmFunctionRegistry sqmFunctionRegistry;
private final int preferredSqlTypeCodeForBoolean;
public QueryEngine(
Supplier<JpaMetamodel> jpaMetamodelAccess,
ValueHandlingMode criteriaValueHandlingMode,
int preferredSqlTypeCodeForBoolean,
NamedObjectRepository namedObjectRepository,
HqlTranslator hqlTranslator,
SqmTranslatorFactory sqmTranslatorFactory,
@ -114,6 +117,7 @@ public class QueryEngine {
);
this.sqmFunctionRegistry = new SqmFunctionRegistry();
this.preferredSqlTypeCodeForBoolean = preferredSqlTypeCodeForBoolean;
dialect.initializeFunctionRegistry( this );
if ( userDefinedRegistry != null ) {
userDefinedRegistry.overlay( sqmFunctionRegistry );
@ -137,6 +141,7 @@ public class QueryEngine {
public QueryEngine(
JpaMetamodel jpaMetamodel,
ValueHandlingMode criteriaValueHandlingMode,
int preferredSqlTypeCodeForBoolean,
boolean useStrictJpaCompliance,
NamedObjectRepository namedObjectRepository,
NativeQueryInterpreter nativeQueryInterpreter,
@ -147,6 +152,7 @@ public class QueryEngine {
this.nativeQueryInterpreter = nativeQueryInterpreter;
this.sqmFunctionRegistry = new SqmFunctionRegistry();
this.preferredSqlTypeCodeForBoolean = preferredSqlTypeCodeForBoolean;
dialect.initializeFunctionRegistry( this );
this.criteriaBuilder = new SqmCriteriaNodeBuilder(
@ -367,4 +373,8 @@ public class QueryEngine {
sqmFunctionRegistry.close();
}
}
public int getPreferredSqlTypeCodeForBoolean() {
return preferredSqlTypeCodeForBoolean;
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.type;
import java.io.Serializable;
import java.sql.Types;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
@ -60,10 +61,12 @@ public class BooleanType
@Override
public <X> BasicType<X> resolveIndicatedType(SqlTypeDescriptorIndicators indicators) {
if ( indicators.getPreferredSqlTypeCodeForBoolean() != getSqlTypeDescriptor().getJdbcTypeCode() ) {
final int preferredSqlTypeCodeForBoolean = indicators.getPreferredSqlTypeCodeForBoolean();
// We treat BIT like BOOLEAN because it uses the same JDBC access methods
if ( preferredSqlTypeCodeForBoolean != Types.BIT && preferredSqlTypeCodeForBoolean != getSqlTypeDescriptor().getJdbcTypeCode() ) {
final SqlTypeDescriptor sqlTypeDescriptor = indicators.getTypeConfiguration()
.getSqlTypeDescriptorRegistry()
.getDescriptor( indicators.getPreferredSqlTypeCodeForBoolean() );
.getDescriptor( preferredSqlTypeCodeForBoolean );
//noinspection unchecked
return (BasicType<X>) indicators.getTypeConfiguration()
.getBasicTypeRegistry()

View File

@ -13,6 +13,7 @@ import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.JpaComplianceStub;
import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
@ -118,6 +119,7 @@ public class HqlTranslationNoFactoryTests {
final QueryEngine queryEngine = new QueryEngine(
jpaMetamodel,
ValueHandlingMode.BIND,
ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( registryScope.getRegistry() ),
// we don't want strict JPA query compliance
false,
new NamedObjectRepositoryImpl( Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap() ),