HHH-17076 - Numeric literal typing
https://hibernate.atlassian.net/browse/HHH-17076
This commit is contained in:
parent
c7ed34d159
commit
ab4ac5a64e
|
@ -62,9 +62,9 @@ INTEGER_LITERAL : INTEGER_NUMBER ('_' INTEGER_NUMBER)*;
|
|||
|
||||
LONG_LITERAL : INTEGER_NUMBER ('_' INTEGER_NUMBER)* LONG_SUFFIX;
|
||||
|
||||
FLOAT_LITERAL : FLOATING_POINT_NUMBER FLOAT_SUFFIX?;
|
||||
FLOAT_LITERAL : FLOATING_POINT_NUMBER FLOAT_SUFFIX;
|
||||
|
||||
DOUBLE_LITERAL : FLOATING_POINT_NUMBER DOUBLE_SUFFIX;
|
||||
DOUBLE_LITERAL : FLOATING_POINT_NUMBER DOUBLE_SUFFIX?;
|
||||
|
||||
BIG_INTEGER_LITERAL : INTEGER_NUMBER BIG_INTEGER_SUFFIX;
|
||||
|
||||
|
|
|
@ -611,6 +611,7 @@ parameterOrIntegerLiteral
|
|||
parameterOrNumberLiteral
|
||||
: parameter
|
||||
| INTEGER_LITERAL
|
||||
| LONG_LITERAL
|
||||
| FLOAT_LITERAL
|
||||
| DOUBLE_LITERAL
|
||||
;
|
||||
|
@ -1006,7 +1007,7 @@ month: INTEGER_LITERAL;
|
|||
day: INTEGER_LITERAL;
|
||||
hour: INTEGER_LITERAL;
|
||||
minute: INTEGER_LITERAL;
|
||||
second: INTEGER_LITERAL | FLOAT_LITERAL;
|
||||
second: INTEGER_LITERAL | DOUBLE_LITERAL;
|
||||
zoneId
|
||||
: IDENTIFIER (SLASH IDENTIFIER)?
|
||||
| STRING_LITERAL;
|
||||
|
|
|
@ -145,6 +145,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
|
||||
|
@ -1791,7 +1792,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
@Override
|
||||
public SqmExpression<?> visitParameterOrIntegerLiteral(HqlParser.ParameterOrIntegerLiteralContext ctx) {
|
||||
if ( ctx.INTEGER_LITERAL() != null ) {
|
||||
return integralLiteral( ctx.INTEGER_LITERAL().getText() );
|
||||
return integerLiteral( ctx.INTEGER_LITERAL().getText() );
|
||||
}
|
||||
else {
|
||||
return (SqmExpression<?>) ctx.parameter().accept( this );
|
||||
|
@ -1801,10 +1802,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
@Override
|
||||
public SqmExpression<?> visitParameterOrNumberLiteral(HqlParser.ParameterOrNumberLiteralContext ctx) {
|
||||
if ( ctx.INTEGER_LITERAL() != null ) {
|
||||
return integralLiteral( ctx.INTEGER_LITERAL().getText() );
|
||||
return integerLiteral( ctx.INTEGER_LITERAL().getText() );
|
||||
}
|
||||
if ( ctx.FLOAT_LITERAL() != null ) {
|
||||
return numericLiteral( ctx.FLOAT_LITERAL().getText() );
|
||||
return floatLiteral( ctx.FLOAT_LITERAL().getText() );
|
||||
}
|
||||
if ( ctx.DOUBLE_LITERAL() != null ) {
|
||||
return doubleLiteral( ctx.DOUBLE_LITERAL().getText() );
|
||||
|
@ -1816,9 +1817,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
if ( firstChild instanceof TerminalNode ) {
|
||||
switch ( ( (TerminalNode) firstChild ).getSymbol().getType() ) {
|
||||
case HqlParser.INTEGER_LITERAL:
|
||||
return integralLiteral( firstChild.getText() );
|
||||
return integerLiteral( firstChild.getText() );
|
||||
case HqlParser.FLOAT_LITERAL:
|
||||
return numericLiteral( firstChild.getText() );
|
||||
return floatLiteral( firstChild.getText() );
|
||||
case HqlParser.DOUBLE_LITERAL:
|
||||
return doubleLiteral( firstChild.getText() );
|
||||
default:
|
||||
|
@ -3224,7 +3225,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
switch ( node.getSymbol().getType() ) {
|
||||
case HqlParser.INTEGER_LITERAL:
|
||||
return integralLiteral( text );
|
||||
return integerLiteral( text );
|
||||
case HqlParser.LONG_LITERAL:
|
||||
return longLiteral( text );
|
||||
case HqlParser.BIG_INTEGER_LITERAL:
|
||||
|
@ -3232,7 +3233,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
case HqlParser.HEX_LITERAL:
|
||||
return hexLiteral( text );
|
||||
case HqlParser.FLOAT_LITERAL:
|
||||
return numericLiteral( text );
|
||||
return floatLiteral( text );
|
||||
case HqlParser.DOUBLE_LITERAL:
|
||||
return doubleLiteral( text );
|
||||
case HqlParser.BIG_DECIMAL_LITERAL:
|
||||
|
@ -3281,7 +3282,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
case HqlParser.JAVA_STRING_LITERAL:
|
||||
return javaStringLiteral( node.getText() );
|
||||
case HqlParser.INTEGER_LITERAL:
|
||||
return integralLiteral( node.getText() );
|
||||
return integerLiteral( node.getText() );
|
||||
case HqlParser.LONG_LITERAL:
|
||||
return longLiteral( node.getText() );
|
||||
case HqlParser.BIG_INTEGER_LITERAL:
|
||||
|
@ -3289,7 +3290,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
case HqlParser.HEX_LITERAL:
|
||||
return hexLiteral( node.getText() );
|
||||
case HqlParser.FLOAT_LITERAL:
|
||||
return numericLiteral( node.getText() );
|
||||
return floatLiteral( node.getText() );
|
||||
case HqlParser.DOUBLE_LITERAL:
|
||||
return doubleLiteral( node.getText() );
|
||||
case HqlParser.BIG_DECIMAL_LITERAL:
|
||||
|
@ -3621,235 +3622,67 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
);
|
||||
}
|
||||
|
||||
private SqmLiteral<? extends Number> integralLiteral(String text) {
|
||||
final String integralText = text.replace( "_", "" );
|
||||
final int decimalNumbers = integralText.length() - ( integralText.charAt( 0 ) == '-' ? 1 : 0 );
|
||||
if ( decimalNumbers > 19 ) {
|
||||
try {
|
||||
final BigInteger value = new BigInteger( integralText );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( BigInteger.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + text + "] to BigInteger",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( decimalNumbers > 10 ) {
|
||||
try {
|
||||
final Long value = Long.valueOf( integralText );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
try {
|
||||
final BigInteger value = new BigInteger( integralText );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( BigInteger.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e2) {
|
||||
final LiteralNumberFormatException exception = new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + text + "] to Long or BigInteger",
|
||||
e
|
||||
);
|
||||
exception.addSuppressed( e );
|
||||
exception.addSuppressed( e2 );
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
final Integer value = Integer.valueOf( integralText );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Integer.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
try {
|
||||
final Long value = Long.valueOf( integralText );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e2) {
|
||||
try {
|
||||
final BigInteger value = new BigInteger( integralText );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( BigInteger.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e3) {
|
||||
final LiteralNumberFormatException exception = new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + text + "] to Integer, Long or BigInteger",
|
||||
e
|
||||
);
|
||||
exception.addSuppressed( e );
|
||||
exception.addSuppressed( e2 );
|
||||
exception.addSuppressed( e3 );
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
private SqmHqlNumericLiteral<Integer> integerLiteral(String text) {
|
||||
return new SqmHqlNumericLiteral<>(
|
||||
text.replace( "_", "" ),
|
||||
integerDomainType,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral<Long> longLiteral(String text) {
|
||||
final String originalText = text;
|
||||
try {
|
||||
if ( text.endsWith( "l" ) || text.endsWith( "L" ) ) {
|
||||
text = text.substring( 0, text.length() - 1 ).replace("_", "");
|
||||
}
|
||||
final Long value = Long.valueOf( text );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + originalText + "] to Long",
|
||||
e
|
||||
);
|
||||
}
|
||||
private SqmHqlNumericLiteral<Long> longLiteral(String text) {
|
||||
assert text.endsWith( "l" ) || text.endsWith( "L" );
|
||||
return new SqmHqlNumericLiteral<>(
|
||||
text.substring( 0, text.length() - 1 ).replace( "_", "" ),
|
||||
resolveExpressibleTypeBasic( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral<? extends Number> hexLiteral(String text) {
|
||||
final String originalText = text;
|
||||
text = text.substring( 2 );
|
||||
try {
|
||||
if ( text.endsWith( "l" ) || text.endsWith( "L" ) ) {
|
||||
text = text.substring( 0, text.length() - 1 );
|
||||
final long value = Long.parseUnsignedLong( text, 16 );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
else {
|
||||
final int value = Integer.parseUnsignedInt( text, 16 );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Integer.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + originalText + "]",
|
||||
e
|
||||
);
|
||||
}
|
||||
private SqmHqlNumericLiteral<BigInteger> bigIntegerLiteral(String text) {
|
||||
assert text.endsWith( "bi" ) || text.endsWith( "BI" );
|
||||
return new SqmHqlNumericLiteral<>(
|
||||
text.substring( 0, text.length() - 2 ).replace( "_", "" ),
|
||||
resolveExpressibleTypeBasic( BigInteger.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral<BigInteger> bigIntegerLiteral(String text) {
|
||||
final String originalText = text;
|
||||
try {
|
||||
if ( text.endsWith( "bi" ) || text.endsWith( "BI" ) ) {
|
||||
text = text.substring( 0, text.length() - 2 );
|
||||
}
|
||||
return new SqmLiteral<>(
|
||||
new BigInteger( text ),
|
||||
resolveExpressibleTypeBasic( BigInteger.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + originalText + "] to BigInteger",
|
||||
e
|
||||
);
|
||||
}
|
||||
private SqmHqlNumericLiteral<? extends Number> floatLiteral(String text) {
|
||||
assert text.endsWith( "f" ) || text.endsWith( "F" );
|
||||
return new SqmHqlNumericLiteral<>(
|
||||
text.substring( 0, text.length() - 1 ).replace( "_", "" ),
|
||||
resolveExpressibleTypeBasic( Float.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral<? extends Number> numericLiteral(String text) {
|
||||
final String numericText = text.replace( "_", "" );
|
||||
final char lastChar = text.charAt( text.length() - 1 );
|
||||
if ( lastChar == 'f' || lastChar == 'F' ) {
|
||||
try {
|
||||
return new SqmLiteral<>(
|
||||
Float.valueOf( numericText ),
|
||||
resolveExpressibleTypeBasic( Float.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + text + "] to Float",
|
||||
e
|
||||
);
|
||||
}
|
||||
private SqmHqlNumericLiteral<Double> doubleLiteral(String text) {
|
||||
if ( text.endsWith( "d" ) || text.endsWith( "D" ) ) {
|
||||
text = text.substring( 0, text.length() - 1 );
|
||||
}
|
||||
return new SqmHqlNumericLiteral<>(
|
||||
text.replace( "_", "" ),
|
||||
resolveExpressibleTypeBasic( Double.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmHqlNumericLiteral<BigDecimal> bigDecimalLiteral(String text) {
|
||||
assert text.endsWith( "bd" ) || text.endsWith( "BD" );
|
||||
return new SqmHqlNumericLiteral<>(
|
||||
text.substring( 0, text.length() - 2 ).replace( "_", "" ),
|
||||
resolveExpressibleTypeBasic( BigDecimal.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmHqlNumericLiteral<? extends Number> hexLiteral(String text) {
|
||||
if ( text.endsWith( "l" ) || text.endsWith( "L" ) ) {
|
||||
return longLiteral( text );
|
||||
}
|
||||
else {
|
||||
// Treat numeric literals without a type suffix like BigDecimal
|
||||
// according to the JPA spec 4.6.1 and SQL spec 5.3
|
||||
try {
|
||||
return new SqmLiteral<>(
|
||||
new BigDecimal( numericText ),
|
||||
resolveExpressibleTypeBasic( BigDecimal.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + text + "] to BigDecimal",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SqmLiteral<Double> doubleLiteral(String text) {
|
||||
try {
|
||||
return new SqmLiteral<>(
|
||||
Double.valueOf( text ),
|
||||
resolveExpressibleTypeBasic( Double.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + text + "] to Double",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private SqmLiteral<BigDecimal> bigDecimalLiteral(String text) {
|
||||
final String originalText = text;
|
||||
try {
|
||||
if ( text.endsWith( "bd" ) || text.endsWith( "BD" ) ) {
|
||||
text = text.substring( 0, text.length() - 2 );
|
||||
}
|
||||
return new SqmLiteral<>(
|
||||
new BigDecimal( text ),
|
||||
resolveExpressibleTypeBasic( BigDecimal.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
"Unable to convert sqm literal [" + originalText + "] to BigDecimal",
|
||||
e
|
||||
);
|
||||
return integerLiteral( text );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.query.TypedParameterValue;
|
|||
import org.hibernate.query.criteria.JpaExpression;
|
||||
import org.hibernate.query.internal.QueryOptionsImpl;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
@ -132,6 +133,10 @@ public abstract class AbstractCommonQueryContract implements CommonQueryContract
|
|||
if ( expression instanceof SqmLiteral<?> ) {
|
||||
fetchValue = ( (SqmLiteral<Number>) expression ).getLiteralValue();
|
||||
}
|
||||
else if ( expression instanceof SqmHqlNumericLiteral ) {
|
||||
final SqmHqlNumericLiteral<Number> hqlNumericLiteral = (SqmHqlNumericLiteral<Number>) expression;
|
||||
fetchValue = hqlNumericLiteral.getTypeCategory().parseLiteralValue( hqlNumericLiteral.getLiteralValue() );
|
||||
}
|
||||
else if ( expression instanceof SqmParameter<?> ) {
|
||||
fetchValue = getParameterValue( (Parameter<Number>) expression );
|
||||
if ( fetchValue == null ) {
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
||||
|
@ -283,6 +284,8 @@ public interface SemanticQueryWalker<T> {
|
|||
|
||||
T visitFieldLiteral(SqmFieldLiteral<?> sqmFieldLiteral);
|
||||
|
||||
<N extends Number> T visitHqlNumericLiteral(SqmHqlNumericLiteral<N> numericLiteral);
|
||||
|
||||
T visitTuple(SqmTuple<?> sqmTuple);
|
||||
|
||||
T visitCollation(SqmCollation sqmCollate);
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
||||
|
@ -1140,6 +1141,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> Object visitHqlNumericLiteral(SqmHqlNumericLiteral<N> numericLiteral) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFullyQualifiedClass(Class namedClass) {
|
||||
return null;
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
||||
|
@ -837,6 +838,11 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
return literal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> Object visitHqlNumericLiteral(SqmHqlNumericLiteral<N> numericLiteral) {
|
||||
return numericLiteral;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitTuple(SqmTuple<?> sqmTuple) {
|
||||
sqmTuple.getGroupedExpressions().forEach( e -> e.accept( this ) );
|
||||
|
|
|
@ -216,6 +216,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
||||
|
@ -338,6 +339,7 @@ import org.hibernate.sql.ast.tree.expression.Star;
|
|||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
|
||||
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
|
||||
import org.hibernate.sql.ast.tree.expression.UnparsedNumericLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.CorrelatedTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.FromClause;
|
||||
|
@ -5506,6 +5508,64 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> Expression visitHqlNumericLiteral(SqmHqlNumericLiteral<N> numericLiteral) {
|
||||
final BasicValuedMapping inferredExpressible = (BasicValuedMapping) getInferredValueMapping();
|
||||
final BasicValuedMapping expressible;
|
||||
if ( inferredExpressible == null ) {
|
||||
expressible = (BasicValuedMapping) determineCurrentExpressible( numericLiteral );
|
||||
}
|
||||
else {
|
||||
expressible = inferredExpressible;
|
||||
}
|
||||
|
||||
final JdbcMapping jdbcMapping = expressible.getJdbcMapping();
|
||||
if ( jdbcMapping.getValueConverter() != null ) {
|
||||
// special case where we need to parse the value in order to apply the conversion
|
||||
return handleConvertedUnparsedNumericLiteral( numericLiteral, expressible );
|
||||
}
|
||||
|
||||
return new UnparsedNumericLiteral<>( numericLiteral.getLiteralValue(), jdbcMapping );
|
||||
}
|
||||
|
||||
private <N extends Number> Expression handleConvertedUnparsedNumericLiteral(
|
||||
SqmHqlNumericLiteral<N> numericLiteral,
|
||||
BasicValuedMapping expressible) {
|
||||
//noinspection rawtypes
|
||||
final BasicValueConverter valueConverter = expressible.getJdbcMapping().getValueConverter();
|
||||
assert valueConverter != null;
|
||||
|
||||
final Number parsedValue = numericLiteral.getTypeCategory().parseLiteralValue( numericLiteral.getLiteralValue() );
|
||||
final Object sqlLiteralValue;
|
||||
if ( valueConverter.getDomainJavaType().isInstance( parsedValue ) ) {
|
||||
//noinspection unchecked
|
||||
sqlLiteralValue = valueConverter.toRelationalValue( parsedValue );
|
||||
}
|
||||
else if ( valueConverter.getRelationalJavaType().isInstance( parsedValue ) ) {
|
||||
sqlLiteralValue = parsedValue;
|
||||
}
|
||||
else if ( Number.class.isAssignableFrom( valueConverter.getRelationalJavaType().getJavaTypeClass() ) ) {
|
||||
//noinspection unchecked
|
||||
sqlLiteralValue = valueConverter.getRelationalJavaType().coerce(
|
||||
parsedValue,
|
||||
creationContext.getSessionFactory()::getTypeConfiguration
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new SemanticException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Literal type '%s' did not match domain type '%s' nor converted type '%s'",
|
||||
parsedValue.getClass(),
|
||||
valueConverter.getDomainJavaType().getJavaTypeClass().getName(),
|
||||
valueConverter.getRelationalJavaType().getJavaTypeClass().getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new QueryLiteral<>( sqlLiteralValue, expressible );
|
||||
}
|
||||
|
||||
private MappingModelExpressible<?> getKeyExpressible(JdbcMappingContainer mappingModelExpressible) {
|
||||
if ( mappingModelExpressible instanceof EntityAssociationMapping ) {
|
||||
return ( (EntityAssociationMapping) mappingModelExpressible ).getKeyTargetMatchPart();
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.query.sqm.tree.expression;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public enum NumericTypeCategory {
|
||||
INTEGER,
|
||||
LONG,
|
||||
BIG_INTEGER,
|
||||
DOUBLE,
|
||||
FLOAT,
|
||||
BIG_DECIMAL;
|
||||
|
||||
public <N extends Number> N parseLiteralValue(String value) {
|
||||
switch ( this ) {
|
||||
case INTEGER: {
|
||||
//noinspection unchecked
|
||||
return (N) Integer.valueOf( value );
|
||||
}
|
||||
case LONG: {
|
||||
//noinspection unchecked
|
||||
return (N) Long.valueOf( value );
|
||||
}
|
||||
case BIG_INTEGER: {
|
||||
//noinspection unchecked
|
||||
return (N) new BigInteger( value );
|
||||
}
|
||||
case DOUBLE: {
|
||||
//noinspection unchecked
|
||||
return (N) Double.valueOf( value );
|
||||
}
|
||||
case FLOAT: {
|
||||
//noinspection unchecked
|
||||
return (N) Float.valueOf( value );
|
||||
}
|
||||
case BIG_DECIMAL: {
|
||||
//noinspection unchecked
|
||||
return (N) new BigDecimal( value );
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to parse numeric literal value `%s` - %s",
|
||||
value,
|
||||
name()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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.query.sqm.tree.expression;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
* Used to model numeric literals found in HQL queries.
|
||||
* <p/>
|
||||
* Used instead of {@link SqmLiteral} which would require parsing the
|
||||
* literal value to the specified number type to avoid loss of precision
|
||||
* due to Float and Double being non-exact types.
|
||||
*
|
||||
* @apiNote Only used for HQL literals because we do not have this problem
|
||||
* with criteria queries where the value given us by user would already be
|
||||
* typed.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmHqlNumericLiteral<N extends Number> extends AbstractSqmExpression<N> {
|
||||
private final String literalValue;
|
||||
private final NumericTypeCategory typeCategory;
|
||||
|
||||
public SqmHqlNumericLiteral(
|
||||
String literalValue,
|
||||
BasicDomainType<N> type,
|
||||
NodeBuilder criteriaBuilder) {
|
||||
this( literalValue, interpretCategory( literalValue, type ), type, criteriaBuilder );
|
||||
}
|
||||
|
||||
public SqmHqlNumericLiteral(
|
||||
String literalValue,
|
||||
NumericTypeCategory typeCategory,
|
||||
BasicDomainType<N> type,
|
||||
NodeBuilder criteriaBuilder) {
|
||||
super( type, criteriaBuilder );
|
||||
this.literalValue = literalValue;
|
||||
this.typeCategory = typeCategory;
|
||||
}
|
||||
|
||||
public String getLiteralValue() {
|
||||
return literalValue;
|
||||
}
|
||||
|
||||
public NumericTypeCategory getTypeCategory() {
|
||||
return typeCategory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDomainType<N> getNodeType() {
|
||||
return (BasicDomainType<N>) super.getNodeType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDomainType<N> getExpressible() {
|
||||
return getNodeType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
return walker.visitHqlNumericLiteral( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( literalValue );
|
||||
|
||||
switch ( typeCategory ) {
|
||||
case BIG_DECIMAL: {
|
||||
sb.append( "bd" );
|
||||
break;
|
||||
}
|
||||
case FLOAT: {
|
||||
sb.append( "f" );
|
||||
break;
|
||||
}
|
||||
case BIG_INTEGER: {
|
||||
sb.append( "bi" );
|
||||
break;
|
||||
}
|
||||
case LONG: {
|
||||
sb.append( "l" );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// nothing to do for double/integer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asLoggableText() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
appendHqlString( stringBuilder );
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmHqlNumericLiteral<N> copy(SqmCopyContext context) {
|
||||
return new SqmHqlNumericLiteral<>( literalValue, typeCategory, getExpressible(), nodeBuilder() );
|
||||
}
|
||||
|
||||
private static <N extends Number> NumericTypeCategory interpretCategory(String literalValue, SqmExpressible<N> type) {
|
||||
assert type != null;
|
||||
|
||||
final JavaType<N> javaTypeDescriptor = type.getExpressibleJavaType();
|
||||
assert javaTypeDescriptor != null;
|
||||
|
||||
final Class<N> javaTypeClass = javaTypeDescriptor.getJavaTypeClass();
|
||||
|
||||
if ( BigDecimal.class.equals( javaTypeClass ) ) {
|
||||
return NumericTypeCategory.BIG_DECIMAL;
|
||||
}
|
||||
|
||||
if ( Double.class.equals( javaTypeClass ) ) {
|
||||
return NumericTypeCategory.DOUBLE;
|
||||
}
|
||||
|
||||
if ( Float.class.equals( javaTypeClass ) ) {
|
||||
return NumericTypeCategory.FLOAT;
|
||||
}
|
||||
|
||||
if ( BigInteger.class.equals( javaTypeClass ) ) {
|
||||
return NumericTypeCategory.BIG_INTEGER;
|
||||
}
|
||||
|
||||
if ( Long.class.equals( javaTypeClass ) ) {
|
||||
return NumericTypeCategory.LONG;
|
||||
}
|
||||
|
||||
if ( Short.class.equals( javaTypeClass )
|
||||
|| Integer.class.equals( javaTypeClass ) ) {
|
||||
return NumericTypeCategory.INTEGER;
|
||||
}
|
||||
|
||||
throw new TypeException( literalValue, javaTypeClass );
|
||||
}
|
||||
|
||||
public static class TypeException extends HibernateException {
|
||||
public TypeException(String literalValue, Class<?> javaType) {
|
||||
super(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unexpected Java type [%s] for numeric literal - %s",
|
||||
javaType.getTypeName(),
|
||||
literalValue
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@ import org.hibernate.sql.ast.tree.expression.Star;
|
|||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
|
||||
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
|
||||
import org.hibernate.sql.ast.tree.expression.UnparsedNumericLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.FromClause;
|
||||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
|
@ -173,6 +174,8 @@ public interface SqlAstWalker {
|
|||
|
||||
void visitQueryLiteral(QueryLiteral<?> queryLiteral);
|
||||
|
||||
<N extends Number> void visitUnparsedNumericLiteral(UnparsedNumericLiteral<N> literal);
|
||||
|
||||
void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression);
|
||||
|
||||
void visitModifiedSubQueryExpression(ModifiedSubQueryExpression expression);
|
||||
|
|
|
@ -133,6 +133,7 @@ import org.hibernate.sql.ast.tree.expression.Star;
|
|||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
|
||||
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
|
||||
import org.hibernate.sql.ast.tree.expression.UnparsedNumericLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.DerivedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.FromClause;
|
||||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
|
@ -6675,6 +6676,11 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
visitLiteral( queryLiteral );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> void visitUnparsedNumericLiteral(UnparsedNumericLiteral<N> literal) {
|
||||
appendSql( literal.getLiteralValue() );
|
||||
}
|
||||
|
||||
private void visitLiteral(Literal literal) {
|
||||
if ( literal.getLiteralValue() == null ) {
|
||||
renderNull( literal );
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.sql.ast.tree.expression.Star;
|
|||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
|
||||
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
|
||||
import org.hibernate.sql.ast.tree.expression.UnparsedNumericLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.FromClause;
|
||||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
|
@ -515,6 +516,10 @@ public class AbstractSqlAstWalker implements SqlAstWalker {
|
|||
public void visitQueryLiteral(QueryLiteral<?> queryLiteral) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> void visitUnparsedNumericLiteral(UnparsedNumericLiteral<N> literal) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.sql.ast.tree.expression.Star;
|
|||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
|
||||
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
|
||||
import org.hibernate.sql.ast.tree.expression.UnparsedNumericLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.FromClause;
|
||||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
|
@ -233,6 +234,11 @@ public class ExpressionReplacementWalker implements SqlAstWalker {
|
|||
doReplaceExpression( queryLiteral );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> void visitUnparsedNumericLiteral(UnparsedNumericLiteral<N> literal) {
|
||||
doReplaceExpression( literal );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) {
|
||||
doReplaceExpression( unaryOperationExpression );
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.sql.ast.tree.expression;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
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.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* A numeric literal coming from an HQL query, which needs special handling
|
||||
*
|
||||
* @see org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UnparsedNumericLiteral<N extends Number> implements Expression, DomainResultProducer<N> {
|
||||
private final String literalValue;
|
||||
private final JdbcMapping jdbcMapping;
|
||||
|
||||
public UnparsedNumericLiteral(String literalValue, JdbcMapping jdbcMapping) {
|
||||
this.literalValue = literalValue;
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
}
|
||||
|
||||
public String getLiteralValue() {
|
||||
return literalValue;
|
||||
}
|
||||
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return jdbcMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMappingContainer getExpressionType() {
|
||||
return getJdbcMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<N> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
final TypeConfiguration typeConfiguration = creationState.getSqlAstCreationState().getCreationContext().getSessionFactory().getTypeConfiguration();
|
||||
|
||||
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
|
||||
this,
|
||||
getJdbcMapping().getJdbcJavaType(),
|
||||
null,
|
||||
typeConfiguration
|
||||
);
|
||||
|
||||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
jdbcMapping
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySqlSelections(DomainResultCreationState creationState) {
|
||||
creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||
this,
|
||||
jdbcMapping.getJdbcJavaType(),
|
||||
null,
|
||||
creationState.getSqlAstCreationState().getCreationContext().getMappingMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(SqlAstWalker sqlTreeWalker) {
|
||||
sqlTreeWalker.visitUnparsedNumericLiteral( this );
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package org.hibernate.orm.test.query;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Andrias Sundskar
|
||||
* @author Nathan Xu
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-14213" )
|
||||
public class IntegerRepresentationLiteralParsingExceptionTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { ExampleEntity.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppropriateExceptionMessageGenerated() {
|
||||
try {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
// 9223372036854775808 is beyond Long range, so an Exception will be thrown
|
||||
entityManager.createQuery( "select count(*) from ExampleEntity where counter = 9223372036854775808L" )
|
||||
.getSingleResult();
|
||||
} );
|
||||
Assert.fail( "Exception should be thrown" );
|
||||
}
|
||||
catch (Exception e) {
|
||||
// without fixing HHH-14213, the following exception would be thrown:
|
||||
// "Could not parse literal [9223372036854775808L] as integer"
|
||||
// which is confusing and misleading
|
||||
Assert.assertTrue( e.getMessage().endsWith( " to Long" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "ExampleEntity")
|
||||
static class ExampleEntity {
|
||||
|
||||
@Id
|
||||
int id;
|
||||
|
||||
long counter;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
@ -57,7 +58,7 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
|
|||
assertThat( caseStatement.getFixture(), instanceOf( SqmPath.class ) );
|
||||
|
||||
assertThat( caseStatement.getOtherwise(), notNullValue() );
|
||||
assertThat( caseStatement.getOtherwise(), instanceOf( SqmLiteral.class ) );
|
||||
assertThat( caseStatement.getOtherwise(), instanceOf( SqmHqlNumericLiteral.class ) );
|
||||
|
||||
assertThat( caseStatement.getWhenFragments().size(), is(1) );
|
||||
}
|
||||
|
@ -79,7 +80,7 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
|
|||
);
|
||||
|
||||
assertThat( caseStatement.getOtherwise(), notNullValue() );
|
||||
assertThat( caseStatement.getOtherwise(), instanceOf( SqmLiteral.class ) );
|
||||
assertThat( caseStatement.getOtherwise(), instanceOf( SqmHqlNumericLiteral.class ) );
|
||||
|
||||
assertThat( caseStatement.getWhenFragments().size(), is(1) );
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.hibernate.orm.test.query.sqm.domain.Person;
|
|||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
|
@ -80,8 +81,8 @@ public class WhereClauseTests extends BaseSqmUnitTest {
|
|||
|
||||
assertThat( relationalPredicate.getSqmOperator(), is( ComparisonOperator.EQUAL ) );
|
||||
|
||||
assertThat( relationalPredicate.getRightHandExpression(), instanceOf( SqmLiteral.class ) );
|
||||
assertThat( ( (SqmLiteral<?>) relationalPredicate.getRightHandExpression() ).getLiteralValue(), is( 311 ) );
|
||||
assertThat( relationalPredicate.getRightHandExpression(), instanceOf( SqmHqlNumericLiteral.class ) );
|
||||
assertThat( ( (SqmHqlNumericLiteral<?>) relationalPredicate.getRightHandExpression() ).getLiteralValue(), is( "311" ) );
|
||||
|
||||
assertThat( relationalPredicate.getLeftHandExpression(), instanceOf( SqmCollectionSize.class ) );
|
||||
|
||||
|
@ -100,8 +101,8 @@ public class WhereClauseTests extends BaseSqmUnitTest {
|
|||
|
||||
assertThat( relationalPredicate.getSqmOperator(), is( ComparisonOperator.GREATER_THAN ) );
|
||||
|
||||
assertThat( relationalPredicate.getRightHandExpression(), instanceOf( SqmLiteral.class ) );
|
||||
assertThat( ( (SqmLiteral<?>) relationalPredicate.getRightHandExpression() ).getLiteralValue(), is( 2 ) );
|
||||
assertThat( relationalPredicate.getRightHandExpression(), instanceOf( SqmHqlNumericLiteral.class ) );
|
||||
assertThat( ( (SqmHqlNumericLiteral<?>) relationalPredicate.getRightHandExpression() ).getLiteralValue(), is( "2" ) );
|
||||
|
||||
assertThat( relationalPredicate.getLeftHandExpression(), instanceOf( SqmPath.class ) );
|
||||
final SqmPath<?> indexPath = (SqmPath<?>) relationalPredicate.getLeftHandExpression();
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolv
|
|||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.UnparsedNumericLiteral;
|
||||
|
||||
import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
|
@ -61,7 +61,7 @@ public class SubqueryTest extends BaseSessionFactoryFunctionalTest {
|
|||
public void render(
|
||||
SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
|
||||
sqlAstArguments.get( 0 ).accept( walker );
|
||||
sqlAppender.appendSql( " limit " + ( (QueryLiteral<?>) sqlAstArguments.get( 1 ) ).getLiteralValue() );
|
||||
sqlAppender.appendSql( " limit " + ( (UnparsedNumericLiteral<?>) sqlAstArguments.get( 1 ) ).getLiteralValue() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,26 @@ earlier versions, see any other pertinent migration guides as well.
|
|||
* link:{docsBase}/6.1/migration-guide/migration-guide.html[6.1 Migration guide]
|
||||
* link:{docsBase}/6.0/migration-guide/migration-guide.html[6.0 Migration guide]
|
||||
|
||||
[[hql-numeric-literal-types]]
|
||||
== HQL Numeric Literal Types
|
||||
|
||||
Version 3.2 of the Jakarta Persistence specification
|
||||
https://github.com/jakartaee/persistence/issues/423[clarifies] the interpretation of
|
||||
numeric literals with regard to type, explicitly aligning with the Java specification (as well
|
||||
as adopting Hibernate's long-standing `BigInteger` and `BigDecimal` suffixes).
|
||||
HQL and JPQL are domain/object-level queries, so that makes perfect sense.
|
||||
|
||||
* `Integer` - 123
|
||||
* `Long` - 123l, 123L
|
||||
* `BigInteger` - 123bi, 123BI
|
||||
* `Double` - 123.4
|
||||
* `Float` - 123.4f, 123.4F
|
||||
* `BigDecimal` - 123.4bd, 123.4BD
|
||||
|
||||
Hibernate 6.3 aligns with those interpretations, which may lead to different behavior
|
||||
from prior versions.
|
||||
|
||||
|
||||
[[batch-fetching-changes]]
|
||||
== Batch Fetching and LockMode
|
||||
|
||||
|
@ -22,8 +42,9 @@ This because the lock mode is different from the one of the proxies in the batch
|
|||
|
||||
E.g.
|
||||
|
||||
`
|
||||
```java
|
||||
MyEntity proxy = session.getReference( MyEntity.class, 1 );
|
||||
MyEntity myEntity = session.find(MyEntity.class, 2, LockMode.WRITE);
|
||||
`
|
||||
```
|
||||
|
||||
only the entity with id equals to 2 will be loaded but the proxy will not be initialized.
|
||||
|
|
Loading…
Reference in New Issue