HHH-16048 add 'hibernate.query.hql.portable_integer_division'
consistent interpretation of division on MySQL and Oracle
This commit is contained in:
parent
a97b7ba611
commit
d7fe31643a
|
@ -129,6 +129,7 @@ import static org.hibernate.cfg.AvailableSettings.USE_SQL_COMMENTS;
|
|||
import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_SUBSELECT_FETCH;
|
||||
import static org.hibernate.cfg.CacheSettings.QUERY_CACHE_LAYOUT;
|
||||
import static org.hibernate.cfg.QuerySettings.PORTABLE_INTEGER_DIVISION;
|
||||
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
||||
|
@ -270,6 +271,8 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private final boolean failOnPaginationOverCollectionFetchEnabled;
|
||||
private final boolean inClauseParameterPaddingEnabled;
|
||||
|
||||
private final boolean portableIntegerDivisionEnabled;
|
||||
|
||||
private final int queryStatisticsMaxSize;
|
||||
|
||||
|
||||
|
@ -591,11 +594,16 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
this.defaultCatalog = getString( DEFAULT_CATALOG, configurationSettings );
|
||||
this.defaultSchema = getString( DEFAULT_SCHEMA, configurationSettings );
|
||||
|
||||
this.inClauseParameterPaddingEnabled = getBoolean(
|
||||
this.inClauseParameterPaddingEnabled = getBoolean(
|
||||
IN_CLAUSE_PARAMETER_PADDING,
|
||||
configurationSettings
|
||||
);
|
||||
|
||||
this.portableIntegerDivisionEnabled = getBoolean(
|
||||
PORTABLE_INTEGER_DIVISION,
|
||||
configurationSettings
|
||||
);
|
||||
|
||||
this.queryStatisticsMaxSize = getInt(
|
||||
QUERY_STATISTICS_MAX_SIZE,
|
||||
configurationSettings,
|
||||
|
@ -1213,6 +1221,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return this.inClauseParameterPaddingEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPortableIntegerDivisionEnabled() {
|
||||
return portableIntegerDivisionEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return jpaCompliance;
|
||||
|
|
|
@ -428,6 +428,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
return delegate.inClauseParameterPaddingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPortableIntegerDivisionEnabled() {
|
||||
return delegate.isPortableIntegerDivisionEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryStatisticsMaxSize() {
|
||||
return delegate.getQueryStatisticsMaxSize();
|
||||
|
|
|
@ -272,10 +272,21 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#IN_CLAUSE_PARAMETER_PADDING
|
||||
*/
|
||||
default boolean inClauseParameterPaddingEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
|
||||
*/
|
||||
@Override
|
||||
default boolean isPortableIntegerDivisionEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default int getQueryStatisticsMaxSize() {
|
||||
return Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,14 @@ import jakarta.persistence.criteria.CriteriaUpdate;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface QuerySettings {
|
||||
/**
|
||||
* Specifies that division of two integers should produce an integer on all
|
||||
* databases. By default, integer division in HQL can produce a non-integer
|
||||
* on Oracle, MySQL, or MariaDB.
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
String PORTABLE_INTEGER_DIVISION = "hibernate.query.hql.portable_integer_division";
|
||||
/**
|
||||
* Specifies a {@link org.hibernate.query.hql.HqlTranslator} to use for HQL query
|
||||
* translation.
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
|||
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -51,6 +52,20 @@ public class MariaDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
|
|||
this.dialect = (MariaDBDialect) DialectDelegateWrapper.extractRealDialect( super.getDialect() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
if ( isIntegerDivisionEmulationRequired( arithmeticExpression ) ) {
|
||||
appendSql( OPEN_PARENTHESIS );
|
||||
arithmeticExpression.getLeftHandOperand().accept( this );
|
||||
appendSql( " div " );
|
||||
arithmeticExpression.getRightHandOperand().accept( this );
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
else {
|
||||
super.visitBinaryArithmeticExpression(arithmeticExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitInsertSource(InsertSelectStatement statement) {
|
||||
if ( statement.getSourceSelectStatement() != null ) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
|||
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -101,6 +102,20 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
|
|||
return sqlType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
if ( isIntegerDivisionEmulationRequired( arithmeticExpression ) ) {
|
||||
appendSql( OPEN_PARENTHESIS );
|
||||
arithmeticExpression.getLeftHandOperand().accept( this );
|
||||
appendSql( " div " );
|
||||
arithmeticExpression.getRightHandOperand().accept( this );
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
else {
|
||||
super.visitBinaryArithmeticExpression(arithmeticExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitInsertSource(InsertSelectStatement statement) {
|
||||
if ( statement.getSourceSelectStatement() != null ) {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.sql.ast.Clause;
|
|||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteMaterialization;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
|
||||
|
@ -587,6 +588,14 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends SqlAstTrans
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
if ( isIntegerDivisionEmulationRequired( arithmeticExpression ) ) {
|
||||
appendSql( "floor" );
|
||||
}
|
||||
super.visitBinaryArithmeticExpression(arithmeticExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsDuplicateSelectItemsInQueryGroup() {
|
||||
return false;
|
||||
|
|
|
@ -17,6 +17,12 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||
import org.hibernate.sql.model.jdbc.OptionalTableUpdateOperation;
|
||||
|
@ -114,4 +120,23 @@ public class PostgresPlusDialect extends PostgreSQLDialect {
|
|||
// https://www.enterprisedb.com/docs/migrating/oracle/oracle_epas_comparison/notable_differences/
|
||||
return new OptionalTableUpdateOperation( mutationTarget, optionalTableUpdate, factory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
|
||||
return new StandardSqlAstTranslatorFactory() {
|
||||
@Override
|
||||
protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
|
||||
SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
return new PostgreSQLSqlAstTranslator<>( sessionFactory, statement ) {
|
||||
@Override
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
if ( isIntegerDivisionEmulationRequired( arithmeticExpression ) ) {
|
||||
appendSql( "floor" );
|
||||
}
|
||||
super.visitBinaryArithmeticExpression(arithmeticExpression);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
|
|||
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType;
|
||||
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Collections;
|
||||
|
@ -40,6 +39,7 @@ import static org.hibernate.query.sqm.BinaryArithmeticOperator.*;
|
|||
import static org.hibernate.query.sqm.TemporalUnit.*;
|
||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
|
||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL_UNIT;
|
||||
import static org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType.ZONE_OFFSET_NAME;
|
||||
|
||||
/**
|
||||
* ANSI SQL-inspired {@code extract()} function, where the date/time fields
|
||||
|
@ -96,7 +96,7 @@ public class ExtractFunction extends AbstractSqmFunctionDescriptor implements Fu
|
|||
case OFFSET:
|
||||
if ( compositeTemporal ) {
|
||||
final SqmPath<Object> offsetPath = ( (SqmPath<?>) originalExpression ).get(
|
||||
AbstractTimeZoneStorageCompositeUserType.ZONE_OFFSET_NAME
|
||||
ZONE_OFFSET_NAME
|
||||
);
|
||||
return new SelfRenderingSqmFunction<>(
|
||||
this,
|
||||
|
|
|
@ -15,8 +15,6 @@ import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
|
@ -29,9 +27,6 @@ import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
|||
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
|
||||
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -40,7 +35,6 @@ import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
|||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Format;
|
||||
|
@ -54,8 +48,16 @@ import org.hibernate.type.SqlTypes;
|
|||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.DIVIDE_PORTABLE;
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.MODULO;
|
||||
import static org.hibernate.query.sqm.ComparisonOperator.GREATER_THAN_OR_EQUAL;
|
||||
import static org.hibernate.query.sqm.ComparisonOperator.LESS_THAN;
|
||||
import static org.hibernate.query.sqm.ComparisonOperator.LESS_THAN_OR_EQUAL;
|
||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
|
||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
|
||||
import static org.hibernate.query.sqm.produce.function.StandardArgumentsValidators.exactly;
|
||||
import static org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers.invariant;
|
||||
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.invariant;
|
||||
|
||||
/**
|
||||
* A format function with support for composite temporal expressions.
|
||||
|
@ -89,10 +91,9 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
TypeConfiguration typeConfiguration) {
|
||||
super(
|
||||
"format",
|
||||
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), TEMPORAL, STRING ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve(
|
||||
StandardBasicTypes.STRING ) ),
|
||||
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL, STRING )
|
||||
new ArgumentTypesValidator( exactly( 2 ), TEMPORAL, STRING ),
|
||||
invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ),
|
||||
invariant( typeConfiguration, TEMPORAL, STRING )
|
||||
);
|
||||
this.nativeFunctionName = nativeFunctionName;
|
||||
this.reversedArguments = reversedArguments;
|
||||
|
@ -260,8 +261,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
"substring",
|
||||
3
|
||||
);
|
||||
final AbstractSqmSelfRenderingFunctionDescriptor floorFunction = getFunction( walker, "floor" );
|
||||
final AbstractSqmSelfRenderingFunctionDescriptor castFunction = getFunction( walker, "cast" );
|
||||
final BasicType<String> stringType = typeConfiguration.getBasicTypeRegistry()
|
||||
.resolve( StandardBasicTypes.STRING );
|
||||
final Dialect dialect = walker.getCreationContext()
|
||||
|
@ -344,8 +343,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
createSmallOffset(
|
||||
concatFunction,
|
||||
substringFunction,
|
||||
floorFunction,
|
||||
castFunction,
|
||||
stringType,
|
||||
integerType,
|
||||
offsetExpression
|
||||
|
@ -365,8 +362,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
createMediumOffset(
|
||||
concatFunction,
|
||||
substringFunction,
|
||||
floorFunction,
|
||||
castFunction,
|
||||
stringType,
|
||||
integerType,
|
||||
offsetExpression
|
||||
|
@ -382,8 +377,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
formatExpression,
|
||||
createFullOffset(
|
||||
concatFunction,
|
||||
floorFunction,
|
||||
castFunction,
|
||||
stringType,
|
||||
integerType,
|
||||
offsetExpression
|
||||
|
@ -491,8 +484,9 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
.getSqmFunctionRegistry()
|
||||
.findFunctionDescriptor( name );
|
||||
if ( functionDescriptor instanceof MultipatternSqmFunctionDescriptor ) {
|
||||
return (AbstractSqmSelfRenderingFunctionDescriptor) ( (MultipatternSqmFunctionDescriptor) functionDescriptor )
|
||||
.getFunction( argumentCount );
|
||||
return (AbstractSqmSelfRenderingFunctionDescriptor)
|
||||
( (MultipatternSqmFunctionDescriptor) functionDescriptor )
|
||||
.getFunction( argumentCount );
|
||||
}
|
||||
return (AbstractSqmSelfRenderingFunctionDescriptor) functionDescriptor;
|
||||
}
|
||||
|
@ -519,8 +513,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
|
||||
private Expression createFullOffset(
|
||||
AbstractSqmSelfRenderingFunctionDescriptor concatFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor floorFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor castFunction,
|
||||
BasicType<String> stringType,
|
||||
BasicType<Integer> integerType,
|
||||
Expression offsetExpression) {
|
||||
|
@ -529,63 +521,18 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
}
|
||||
else {
|
||||
// ZoneOffset as seconds
|
||||
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression( stringType );
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.LESS_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>(
|
||||
-36000,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "-", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.LESS_THAN,
|
||||
new QueryLiteral<>(
|
||||
0,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "-0", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.GREATER_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>(
|
||||
36000,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "+", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.otherwise( new QueryLiteral<>( "+0", stringType ) );
|
||||
final Expression hours = getHours( floorFunction, castFunction, integerType, offsetExpression );
|
||||
final Expression minutes = getMinutes( floorFunction, castFunction, integerType, offsetExpression );
|
||||
final CaseSearchedExpression caseSearchedExpression =
|
||||
zoneOffsetSeconds( stringType, integerType, offsetExpression );
|
||||
final Expression hours = getHours( integerType, offsetExpression );
|
||||
final Expression minutes = getMinutes( integerType, offsetExpression );
|
||||
|
||||
final CaseSearchedExpression minuteStart = new CaseSearchedExpression( stringType );
|
||||
minuteStart.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new BetweenPredicate(
|
||||
minutes,
|
||||
new QueryLiteral<>(
|
||||
-9,
|
||||
integerType
|
||||
),
|
||||
new QueryLiteral<>(
|
||||
9,
|
||||
integerType
|
||||
),
|
||||
new QueryLiteral<>( -9, integerType ),
|
||||
new QueryLiteral<>( 9, integerType ),
|
||||
false,
|
||||
null
|
||||
),
|
||||
|
@ -610,8 +557,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
private Expression createMediumOffset(
|
||||
AbstractSqmSelfRenderingFunctionDescriptor concatFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor substringFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor floorFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor castFunction,
|
||||
BasicType<String> stringType,
|
||||
BasicType<Integer> integerType,
|
||||
Expression offsetExpression) {
|
||||
|
@ -622,8 +567,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
createSmallOffset(
|
||||
concatFunction,
|
||||
substringFunction,
|
||||
floorFunction,
|
||||
castFunction,
|
||||
stringType,
|
||||
integerType,
|
||||
offsetExpression
|
||||
|
@ -643,64 +586,19 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
}
|
||||
else {
|
||||
// ZoneOffset as seconds
|
||||
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression( stringType );
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.LESS_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>(
|
||||
-36000,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "-", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.LESS_THAN,
|
||||
new QueryLiteral<>(
|
||||
0,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "-0", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.GREATER_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>(
|
||||
36000,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "+", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.otherwise( new QueryLiteral<>( "+0", stringType ) );
|
||||
final CaseSearchedExpression caseSearchedExpression =
|
||||
zoneOffsetSeconds( stringType, integerType, offsetExpression );
|
||||
|
||||
final Expression hours = getHours( floorFunction, castFunction, integerType, offsetExpression );
|
||||
final Expression minutes = getMinutes( floorFunction, castFunction, integerType, offsetExpression );
|
||||
final Expression hours = getHours( integerType, offsetExpression );
|
||||
final Expression minutes = getMinutes( integerType, offsetExpression );
|
||||
|
||||
final CaseSearchedExpression minuteStart = new CaseSearchedExpression( stringType );
|
||||
minuteStart.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new BetweenPredicate(
|
||||
minutes,
|
||||
new QueryLiteral<>(
|
||||
-9,
|
||||
integerType
|
||||
),
|
||||
new QueryLiteral<>(
|
||||
9,
|
||||
integerType
|
||||
),
|
||||
new QueryLiteral<>( -9, integerType ),
|
||||
new QueryLiteral<>( 9, integerType ),
|
||||
false,
|
||||
null
|
||||
),
|
||||
|
@ -725,8 +623,6 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
private Expression createSmallOffset(
|
||||
AbstractSqmSelfRenderingFunctionDescriptor concatFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor substringFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor floorFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor castFunction,
|
||||
BasicType<String> stringType,
|
||||
BasicType<Integer> integerType,
|
||||
Expression offsetExpression) {
|
||||
|
@ -745,48 +641,9 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
}
|
||||
else {
|
||||
// ZoneOffset as seconds
|
||||
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression( stringType );
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.LESS_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>(
|
||||
-36000,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "-", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.LESS_THAN,
|
||||
new QueryLiteral<>(
|
||||
0,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "-0", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
ComparisonOperator.GREATER_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>(
|
||||
36000,
|
||||
integerType
|
||||
)
|
||||
),
|
||||
new QueryLiteral<>( "+", stringType )
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.otherwise( new QueryLiteral<>( "+0", stringType ) );
|
||||
final Expression hours = getHours( floorFunction, castFunction, integerType, offsetExpression );
|
||||
final CaseSearchedExpression caseSearchedExpression =
|
||||
zoneOffsetSeconds( stringType, integerType, offsetExpression );
|
||||
final Expression hours = getHours( integerType, offsetExpression );
|
||||
return concat( concatFunction, stringType, caseSearchedExpression, hours );
|
||||
}
|
||||
}
|
||||
|
@ -844,7 +701,8 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
}
|
||||
else if ( expression2 instanceof SelfRenderingFunctionSqlAstExpression
|
||||
&& "concat".equals( ( (SelfRenderingFunctionSqlAstExpression) expression2 ).getFunctionName() ) ) {
|
||||
List<SqlAstNode> list = (List<SqlAstNode>) ( (SelfRenderingFunctionSqlAstExpression) expression2 ).getArguments();
|
||||
final List<SqlAstNode> list = (List<SqlAstNode>)
|
||||
( (SelfRenderingFunctionSqlAstExpression) expression2 ).getArguments();
|
||||
final SqlAstNode firstOperand = list.get( 0 );
|
||||
if ( expression instanceof QueryLiteral<?> && firstOperand instanceof QueryLiteral<?> ) {
|
||||
list.set(
|
||||
|
@ -883,68 +741,84 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
|
|||
}
|
||||
|
||||
private Expression getHours(
|
||||
AbstractSqmSelfRenderingFunctionDescriptor floorFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor castFunction,
|
||||
BasicType<Integer> integerType,
|
||||
Expression offsetExpression) {
|
||||
return new SelfRenderingFunctionSqlAstExpression(
|
||||
return /*new SelfRenderingFunctionSqlAstExpression(
|
||||
"cast",
|
||||
castFunction,
|
||||
List.of(
|
||||
new SelfRenderingFunctionSqlAstExpression(
|
||||
"floor",
|
||||
floorFunction,
|
||||
List.of(
|
||||
new BinaryArithmeticExpression(
|
||||
offsetExpression,
|
||||
BinaryArithmeticOperator.DIVIDE,
|
||||
new QueryLiteral<>( 3600, integerType ),
|
||||
integerType
|
||||
)
|
||||
),
|
||||
integerType,
|
||||
List.of(*/
|
||||
new BinaryArithmeticExpression(
|
||||
offsetExpression,
|
||||
DIVIDE_PORTABLE,
|
||||
new QueryLiteral<>( 3600, integerType ),
|
||||
integerType
|
||||
),
|
||||
)/*,
|
||||
new CastTarget( integerType )
|
||||
),
|
||||
integerType,
|
||||
integerType
|
||||
);
|
||||
)*/;
|
||||
}
|
||||
|
||||
private Expression getMinutes(
|
||||
AbstractSqmSelfRenderingFunctionDescriptor floorFunction,
|
||||
AbstractSqmSelfRenderingFunctionDescriptor castFunction,
|
||||
BasicType<Integer> integerType,
|
||||
Expression offsetExpression){
|
||||
return new SelfRenderingFunctionSqlAstExpression(
|
||||
return /*new SelfRenderingFunctionSqlAstExpression(
|
||||
"cast",
|
||||
castFunction,
|
||||
List.of(
|
||||
new SelfRenderingFunctionSqlAstExpression(
|
||||
"floor",
|
||||
floorFunction,
|
||||
List.of(
|
||||
new BinaryArithmeticExpression(
|
||||
new BinaryArithmeticExpression(
|
||||
offsetExpression,
|
||||
BinaryArithmeticOperator.MODULO,
|
||||
new QueryLiteral<>( 3600, integerType ),
|
||||
integerType
|
||||
),
|
||||
BinaryArithmeticOperator.DIVIDE,
|
||||
new QueryLiteral<>( 60, integerType ),
|
||||
integerType
|
||||
)
|
||||
List.of(*/
|
||||
new BinaryArithmeticExpression(
|
||||
new BinaryArithmeticExpression(
|
||||
offsetExpression,
|
||||
MODULO,
|
||||
new QueryLiteral<>( 3600, integerType ),
|
||||
integerType
|
||||
),
|
||||
integerType,
|
||||
DIVIDE_PORTABLE,
|
||||
new QueryLiteral<>( 60, integerType ),
|
||||
integerType
|
||||
),
|
||||
)/*,
|
||||
new CastTarget( integerType )
|
||||
),
|
||||
integerType,
|
||||
integerType
|
||||
);
|
||||
)*/;
|
||||
}
|
||||
}
|
||||
|
||||
private static CaseSearchedExpression zoneOffsetSeconds(BasicType<String> stringType, BasicType<Integer> integerType, Expression offsetExpression) {
|
||||
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression(stringType);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
LESS_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>( -36000, integerType)
|
||||
),
|
||||
new QueryLiteral<>( "-", stringType)
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
LESS_THAN,
|
||||
new QueryLiteral<>( 0, integerType)
|
||||
),
|
||||
new QueryLiteral<>( "-0", stringType)
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.getWhenFragments().add(
|
||||
new CaseSearchedExpression.WhenFragment(
|
||||
new ComparisonPredicate(
|
||||
offsetExpression,
|
||||
GREATER_THAN_OR_EQUAL,
|
||||
new QueryLiteral<>( 36000, integerType)
|
||||
),
|
||||
new QueryLiteral<>( "+", stringType)
|
||||
)
|
||||
);
|
||||
caseSearchedExpression.otherwise( new QueryLiteral<>( "+0", stringType) );
|
||||
return caseSearchedExpression;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.dialect.function;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -28,6 +27,9 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.DIVIDE;
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.MULTIPLY;
|
||||
|
||||
/**
|
||||
* Used in place of {@link TimestampaddFunction} for databases which don't
|
||||
* support fractional seconds in the {@code timestampadd()} function.
|
||||
|
@ -110,11 +112,10 @@ public class IntegralTimestampaddFunction
|
|||
? magnitude
|
||||
: new BinaryArithmeticExpression(
|
||||
magnitude,
|
||||
conversionFactor.charAt(0) == '*'
|
||||
? BinaryArithmeticOperator.MULTIPLY
|
||||
: BinaryArithmeticOperator.DIVIDE,
|
||||
conversionFactor.charAt(0) == '*' ? MULTIPLY : DIVIDE,
|
||||
new QueryLiteral<>(
|
||||
expressionType.getExpressibleJavaType().fromString( conversionFactor.substring(1) ),
|
||||
expressionType.getExpressibleJavaType()
|
||||
.fromString( conversionFactor.substring(1) ),
|
||||
expressionType
|
||||
),
|
||||
expressionType
|
||||
|
|
|
@ -888,7 +888,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
|
||||
private void applyCycleClause(JpaCteCriteria<?> cteDefinition, HqlParser.CycleClauseContext ctx) {
|
||||
final HqlParser.CteAttributesContext attributesContext = (HqlParser.CteAttributesContext) ctx.getChild( 1 );
|
||||
final HqlParser.CteAttributesContext attributesContext = ctx.cteAttributes();
|
||||
final String cycleMarkAttributeName = visitIdentifier( (HqlParser.IdentifierContext) ctx.getChild( 3 ) );
|
||||
final List<JpaCteCriteriaAttribute> cycleAttributes = new ArrayList<>( ( attributesContext.getChildCount() + 1 ) >> 1 );
|
||||
final List<ParseTree> children = attributesContext.children;
|
||||
|
@ -948,14 +948,14 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
else {
|
||||
kind = CteSearchClauseKind.DEPTH_FIRST;
|
||||
}
|
||||
final String searchAttributeName = visitIdentifier( (HqlParser.IdentifierContext) ctx.getChild( ctx.getChildCount() - 1 ) );
|
||||
final HqlParser.SearchSpecificationsContext searchCtx = (HqlParser.SearchSpecificationsContext) ctx.getChild( 4 );
|
||||
final String searchAttributeName = visitIdentifier( ctx.identifier() );
|
||||
final HqlParser.SearchSpecificationsContext searchCtx = ctx.searchSpecifications();
|
||||
final List<JpaSearchOrder> searchOrders = new ArrayList<>( ( searchCtx.getChildCount() + 1 ) >> 1 );
|
||||
final List<ParseTree> children = searchCtx.children;
|
||||
final JpaCteCriteriaType<?> type = cteDefinition.getType();
|
||||
for ( int i = 0; i < children.size(); i += 2 ) {
|
||||
final HqlParser.SearchSpecificationContext specCtx = (HqlParser.SearchSpecificationContext) children.get( i );
|
||||
final String attributeName = visitIdentifier( (HqlParser.IdentifierContext) specCtx.getChild( 0 ) );
|
||||
final String attributeName = visitIdentifier( specCtx.identifier() );
|
||||
final JpaCteCriteriaAttribute attribute = type.getAttribute( attributeName );
|
||||
if ( attribute == null ) {
|
||||
throw new SemanticException(
|
||||
|
@ -972,7 +972,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
int index = 1;
|
||||
if ( index < specCtx.getChildCount() ) {
|
||||
if ( specCtx.getChild( index ) instanceof HqlParser.SortDirectionContext ) {
|
||||
final HqlParser.SortDirectionContext sortCtx = (HqlParser.SortDirectionContext) specCtx.getChild( index );
|
||||
final HqlParser.SortDirectionContext sortCtx = specCtx.sortDirection();
|
||||
switch ( ( (TerminalNode) sortCtx.getChild( 0 ) ).getSymbol().getType() ) {
|
||||
case HqlParser.ASC:
|
||||
sortOrder = SortDirection.ASCENDING;
|
||||
|
@ -986,7 +986,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
index++;
|
||||
}
|
||||
if ( index < specCtx.getChildCount() ) {
|
||||
final HqlParser.NullsPrecedenceContext nullsPrecedenceContext = (HqlParser.NullsPrecedenceContext) specCtx.getChild( index );
|
||||
final HqlParser.NullsPrecedenceContext nullsPrecedenceContext = specCtx.nullsPrecedence();
|
||||
switch ( ( (TerminalNode) nullsPrecedenceContext.getChild( 1 ) ).getSymbol().getType() ) {
|
||||
case HqlParser.FIRST:
|
||||
nullPrecedence = NullPrecedence.FIRST;
|
||||
|
@ -999,13 +999,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
}
|
||||
}
|
||||
searchOrders.add(
|
||||
creationContext.getNodeBuilder().search(
|
||||
attribute,
|
||||
sortOrder,
|
||||
nullPrecedence
|
||||
)
|
||||
);
|
||||
searchOrders.add( creationContext.getNodeBuilder().search( attribute, sortOrder, nullPrecedence ) );
|
||||
}
|
||||
cteDefinition.search( kind, searchAttributeName, searchOrders );
|
||||
}
|
||||
|
@ -1023,7 +1017,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
public SqmQueryPart<?> visitQueryOrderExpression(HqlParser.QueryOrderExpressionContext ctx) {
|
||||
final SqmQuerySpec<?> sqmQuerySpec = currentQuerySpec();
|
||||
final SqmFromClause fromClause = buildInferredFromClause(null);
|
||||
sqmQuerySpec.setFromClause(fromClause);
|
||||
sqmQuerySpec.setFromClause( fromClause );
|
||||
sqmQuerySpec.setSelectClause( buildInferredSelectClause( fromClause ) );
|
||||
visitQueryOrder( sqmQuerySpec, ctx.queryOrder() );
|
||||
return sqmQuerySpec;
|
||||
|
@ -3050,7 +3044,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
case HqlParser.ASTERISK:
|
||||
return BinaryArithmeticOperator.MULTIPLY;
|
||||
case HqlParser.SLASH:
|
||||
return BinaryArithmeticOperator.DIVIDE;
|
||||
return this.creationOptions.isPortableIntegerDivisionEnabled()
|
||||
? BinaryArithmeticOperator.DIVIDE_PORTABLE
|
||||
: BinaryArithmeticOperator.DIVIDE;
|
||||
case HqlParser.PERCENT_OP:
|
||||
return BinaryArithmeticOperator.MODULO;
|
||||
default:
|
||||
|
|
|
@ -22,5 +22,14 @@ public interface SqmCreationOptions {
|
|||
*
|
||||
* @see StrictJpaComplianceViolation
|
||||
*/
|
||||
boolean useStrictJpaCompliance();
|
||||
default boolean useStrictJpaCompliance() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
|
||||
*/
|
||||
default boolean isPortableIntegerDivisionEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ public class QueryEngineImpl implements QueryEngine {
|
|||
|
||||
private static List<FunctionContributor> sortedFunctionContributors(ServiceRegistry serviceRegistry) {
|
||||
Collection<FunctionContributor> functionContributors =
|
||||
serviceRegistry.getService(ClassLoaderService.class)
|
||||
serviceRegistry.requireService(ClassLoaderService.class)
|
||||
.loadJavaServices(FunctionContributor.class);
|
||||
List<FunctionContributor> contributors = new ArrayList<>( functionContributors );
|
||||
contributors.sort(
|
||||
|
|
|
@ -72,4 +72,10 @@ public interface QueryEngineOptions {
|
|||
JpaCompliance getJpaCompliance();
|
||||
|
||||
ValueHandlingMode getCriteriaValueHandlingMode();
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
|
||||
*/
|
||||
boolean isPortableIntegerDivisionEnabled();
|
||||
|
||||
}
|
||||
|
|
|
@ -85,6 +85,25 @@ public enum BinaryArithmeticOperator {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* "Portable" division, that is, true integer division when the
|
||||
* operands are integers.
|
||||
*
|
||||
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
|
||||
* @see org.hibernate.query.spi.QueryEngineOptions#isPortableIntegerDivisionEnabled()
|
||||
*/
|
||||
DIVIDE_PORTABLE {
|
||||
@Override
|
||||
public String toLoggableText(String lhs, String rhs) {
|
||||
return standardToLoggableText( lhs, this, rhs );
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getOperatorSqlText() {
|
||||
return '/';
|
||||
}
|
||||
},
|
||||
|
||||
;
|
||||
|
||||
public abstract String toLoggableText(String lhs, String rhs);
|
||||
|
|
|
@ -23,4 +23,9 @@ public class SqmCreationOptionsStandard implements SqmCreationOptions {
|
|||
public boolean useStrictJpaCompliance() {
|
||||
return queryEngineOptions.getJpaCompliance().isJpaQueryComplianceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPortableIntegerDivisionEnabled() {
|
||||
return queryEngineOptions.isPortableIntegerDivisionEnabled();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
|||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
|
@ -64,7 +63,6 @@ import org.hibernate.persister.internal.SqlFragmentPredicate;
|
|||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.SortDirection;
|
||||
import org.hibernate.query.results.TableGroupImpl;
|
||||
import org.hibernate.query.spi.Limit;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
|
@ -81,7 +79,6 @@ import org.hibernate.query.sqm.function.MultipatternSqmFunctionDescriptor;
|
|||
import org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.sql.internal.EntityValuedPathInterpretation;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
|
||||
import org.hibernate.query.sqm.tree.expression.Conversion;
|
||||
|
@ -227,6 +224,7 @@ import org.hibernate.type.descriptor.sql.DdlType;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.DIVIDE_PORTABLE;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.NANOSECOND;
|
||||
import static org.hibernate.sql.ast.SqlTreePrinter.logSqlAst;
|
||||
import static org.hibernate.sql.results.graph.DomainResultGraphPrinter.logDomainResultGraph;
|
||||
|
@ -1318,6 +1316,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
visitReturningColumns( statement.getReturningColumns() );
|
||||
}
|
||||
|
||||
protected boolean isIntegerDivisionEmulationRequired(BinaryArithmeticExpression expression) {
|
||||
return expression.getOperator() == DIVIDE_PORTABLE
|
||||
&& jdbcType( expression.getLeftHandOperand() ).isInteger()
|
||||
&& jdbcType( expression.getRightHandOperand() ).isInteger();
|
||||
}
|
||||
|
||||
private JdbcType jdbcType(Expression expression) {
|
||||
return expression.getExpressionType().getSingleJdbcMapping().getJdbcType();
|
||||
}
|
||||
|
||||
protected void visitInsertSource(InsertSelectStatement statement) {
|
||||
if ( statement.getSourceSelectStatement() != null ) {
|
||||
statement.getSourceSelectStatement().accept( this );
|
||||
|
@ -7149,8 +7157,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
|
||||
@Override
|
||||
public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
|
||||
final EntityMappingType entityMapping = expression.getEntityTypeDescriptor();
|
||||
appendSql( entityMapping.getDiscriminatorSQLValue() );
|
||||
appendSql( expression.getEntityTypeDescriptor().getDiscriminatorSQLValue() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -61,9 +61,11 @@ import static org.hamcrest.CoreMatchers.*;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
import static org.hibernate.cfg.QuerySettings.PORTABLE_INTEGER_DIVISION;
|
||||
import static org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.FEMALE;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hibernate.cfg.QuerySettings.PORTABLE_INTEGER_DIVISION;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
@DomainModel
|
||||
@SessionFactory
|
||||
@ServiceRegistry(settings = @Setting(name = PORTABLE_INTEGER_DIVISION, value = "true"))
|
||||
public class IntegerDivisionTest {
|
||||
@Test
|
||||
public void testIntegerDivision(SessionFactoryScope scope) {
|
||||
scope.inTransaction(s -> {
|
||||
assertFalse( s.createQuery("select 1 where 1/2 = 0 and 4/3 = 1", Integer.class)
|
||||
.getResultList().isEmpty() );
|
||||
assertEquals( 1, s.createQuery("select 4/3", Integer.class)
|
||||
.getSingleResult() );
|
||||
});
|
||||
}
|
||||
}
|
|
@ -86,6 +86,7 @@ import org.hibernate.proxy.EntityNotFoundDelegate;
|
|||
import org.hibernate.query.criteria.ValueHandlingMode;
|
||||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.hql.internal.StandardHqlTranslator;
|
||||
import org.hibernate.query.hql.spi.SqmCreationOptions;
|
||||
import org.hibernate.query.internal.NamedObjectRepositoryImpl;
|
||||
import org.hibernate.query.internal.QueryInterpretationCacheDisabledImpl;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
|
@ -478,7 +479,7 @@ public abstract class MockSessionFactory
|
|||
|
||||
@Override
|
||||
public HqlTranslator getHqlTranslator() {
|
||||
return new StandardHqlTranslator(MockSessionFactory.this, () -> false);
|
||||
return new StandardHqlTranslator(MockSessionFactory.this, new SqmCreationOptions() {});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.grammars.hql.HqlLexer;
|
|||
import org.hibernate.grammars.hql.HqlParser;
|
||||
import org.hibernate.query.hql.internal.HqlParseTreeBuilder;
|
||||
import org.hibernate.query.hql.internal.SemanticQueryBuilder;
|
||||
import org.hibernate.query.hql.spi.SqmCreationOptions;
|
||||
import org.hibernate.query.sqm.EntityTypeException;
|
||||
import org.hibernate.query.sqm.PathElementException;
|
||||
import org.hibernate.query.sqm.TerminalPathException;
|
||||
|
@ -99,6 +100,9 @@ public class Validation {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static final SqmCreationOptions CREATION_OPTIONS = new SqmCreationOptions() {
|
||||
};
|
||||
|
||||
private static SemanticQueryBuilder<?> createSemanticQueryBuilder(
|
||||
@Nullable TypeMirror returnType, String hql, SessionFactoryImplementor factory) {
|
||||
if ( returnType != null && returnType.getKind() == TypeKind.DECLARED ) {
|
||||
|
@ -107,11 +111,11 @@ public class Validation {
|
|||
final String typeName = typeElement.getQualifiedName().toString();
|
||||
final String shortName = typeElement.getSimpleName().toString();
|
||||
return isEntity( typeElement )
|
||||
? new SemanticQueryBuilder<>( typeName, shortName, getEntityName(typeElement), () -> false, factory, hql )
|
||||
: new SemanticQueryBuilder<>( typeName, shortName, Object[].class, () -> false, factory, hql );
|
||||
? new SemanticQueryBuilder<>( typeName, shortName, getEntityName(typeElement), CREATION_OPTIONS, factory, hql )
|
||||
: new SemanticQueryBuilder<>( typeName, shortName, Object[].class, CREATION_OPTIONS, factory, hql );
|
||||
}
|
||||
else {
|
||||
return new SemanticQueryBuilder<>( Object[].class, () -> false, factory, hql );
|
||||
return new SemanticQueryBuilder<>( Object[].class, CREATION_OPTIONS, factory, hql );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue