Skip to content

Commit

Permalink
HHH-16737 Parse non-type-suffixed number literals as types that fit t…
Browse files Browse the repository at this point in the history
…he number value
  • Loading branch information
beikov committed Aug 3, 2023
1 parent 35a671e commit a209b7a
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private Expression convertedArgument(DurationUnit field, TemporalUnit unit, Expr

private TemporalUnit bestTemporalUnit(Expression magnitude, DurationUnit field) {
final JdbcType jdbcType = magnitude.getExpressionType().getSingleJdbcMapping().getJdbcType();
if ( jdbcType.isFloat() ) {
if ( jdbcType.isFloat() || jdbcType.isDecimal() ) {
// We need to multiply the magnitude by the conversion factor and cast to int
// Use second by default and nanosecond if we encounter fractional seconds
return field.getUnit() == TemporalUnit.SECOND
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ public SqmExpression<?> visitFunctionExpression(HqlParser.FunctionExpressionCont
@Override
public SqmExpression<?> visitParameterOrIntegerLiteral(HqlParser.ParameterOrIntegerLiteralContext ctx) {
if ( ctx.INTEGER_LITERAL() != null ) {
return integerLiteral( ctx.INTEGER_LITERAL().getText() );
return integralLiteral( ctx.INTEGER_LITERAL().getText() );
}
else {
return (SqmExpression<?>) ctx.parameter().accept( this );
Expand All @@ -1801,10 +1801,10 @@ public SqmExpression<?> visitParameterOrIntegerLiteral(HqlParser.ParameterOrInte
@Override
public SqmExpression<?> visitParameterOrNumberLiteral(HqlParser.ParameterOrNumberLiteralContext ctx) {
if ( ctx.INTEGER_LITERAL() != null ) {
return integerLiteral( ctx.INTEGER_LITERAL().getText() );
return integralLiteral( ctx.INTEGER_LITERAL().getText() );
}
if ( ctx.FLOAT_LITERAL() != null ) {
return floatLiteral( ctx.FLOAT_LITERAL().getText() );
return numericLiteral( ctx.FLOAT_LITERAL().getText() );
}
if ( ctx.DOUBLE_LITERAL() != null ) {
return doubleLiteral( ctx.DOUBLE_LITERAL().getText() );
Expand All @@ -1816,9 +1816,9 @@ public SqmExpression<?> visitParameterOrNumberLiteral(HqlParser.ParameterOrNumbe
if ( firstChild instanceof TerminalNode ) {
switch ( ( (TerminalNode) firstChild ).getSymbol().getType() ) {
case HqlParser.INTEGER_LITERAL:
return integerLiteral( firstChild.getText() );
return integralLiteral( firstChild.getText() );
case HqlParser.FLOAT_LITERAL:
return floatLiteral( firstChild.getText() );
return numericLiteral( firstChild.getText() );
case HqlParser.DOUBLE_LITERAL:
return doubleLiteral( firstChild.getText() );
default:
Expand Down Expand Up @@ -2107,7 +2107,7 @@ private <T> void consumeCrossJoin(HqlParser.CrossJoinContext parserJoin, SqmRoot
}
final SqmCrossJoin<T> join =
new SqmCrossJoin<>( entityDescriptor, visitVariable( parserJoin.variable() ), sqmRoot );

processingStateStack.getCurrent().getPathRegistry().register( join );

// CROSS joins are always added to the root
Expand Down Expand Up @@ -3224,15 +3224,15 @@ public SqmExpression<?> visitUnaryNumericLiteralExpression(HqlParser.UnaryNumeri
}
switch ( node.getSymbol().getType() ) {
case HqlParser.INTEGER_LITERAL:
return integerOrLongLiteral( text );
return integralLiteral( text );
case HqlParser.LONG_LITERAL:
return longLiteral( text );
case HqlParser.BIG_INTEGER_LITERAL:
return bigIntegerLiteral( text );
case HqlParser.HEX_LITERAL:
return hexLiteral( text );
case HqlParser.FLOAT_LITERAL:
return floatLiteral( text );
return numericLiteral( text );
case HqlParser.DOUBLE_LITERAL:
return doubleLiteral( text );
case HqlParser.BIG_DECIMAL_LITERAL:
Expand Down Expand Up @@ -3281,15 +3281,15 @@ public SqmExpression<?> visitTerminal(TerminalNode node) {
case HqlParser.JAVA_STRING_LITERAL:
return javaStringLiteral( node.getText() );
case HqlParser.INTEGER_LITERAL:
return integerOrLongLiteral( node.getText() );
return integralLiteral( node.getText() );
case HqlParser.LONG_LITERAL:
return longLiteral( node.getText() );
case HqlParser.BIG_INTEGER_LITERAL:
return bigIntegerLiteral( node.getText() );
case HqlParser.HEX_LITERAL:
return hexLiteral( node.getText() );
case HqlParser.FLOAT_LITERAL:
return floatLiteral( node.getText() );
return numericLiteral( node.getText() );
case HqlParser.DOUBLE_LITERAL:
return doubleLiteral( node.getText() );
case HqlParser.BIG_DECIMAL_LITERAL:
Expand Down Expand Up @@ -3621,49 +3621,91 @@ private SqmLiteral<byte[]> binaryLiteral(String text) {
);
}

private SqmLiteral<? extends Number> integerOrLongLiteral(String text) {
try {
final Integer value = Integer.valueOf( text.replace("_", "") );
return new SqmLiteral<>(
value,
resolveExpressibleTypeBasic( Integer.class ),
creationContext.getNodeBuilder()
);
}
catch (NumberFormatException e) {
// This is at least what 5.x did
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 Long value = Long.valueOf( text );
final BigInteger value = new BigInteger( integralText );
return new SqmLiteral<>(
value,
resolveExpressibleTypeBasic( Long.class ),
resolveExpressibleTypeBasic( BigInteger.class ),
creationContext.getNodeBuilder()
);
}
catch (NumberFormatException e2) {
e.addSuppressed( e2 );
catch (NumberFormatException e) {
throw new LiteralNumberFormatException(
"Unable to convert sqm literal [" + text + "] to Integer",
"Unable to convert sqm literal [" + text + "] to BigInteger",
e
);
}
}
}

private SqmLiteral<Integer> integerLiteral(String text) {
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( text.replace("_", "") );
final Integer value = Integer.valueOf( integralText );
return new SqmLiteral<>(
value,
resolveExpressibleTypeBasic( Integer.class ),
creationContext.getNodeBuilder()
);
}
catch (NumberFormatException e) {
throw new LiteralNumberFormatException(
"Unable to convert sqm literal [" + text + "] to Integer",
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;
}
}
}
}

Expand Down Expand Up @@ -3738,19 +3780,40 @@ private SqmLiteral<BigInteger> bigIntegerLiteral(String text) {
}
}

private SqmLiteral<Float> floatLiteral(String text) {
try {
return new SqmLiteral<>(
Float.valueOf( text ),
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
);
}
}
catch (NumberFormatException e) {
throw new LiteralNumberFormatException(
"Unable to convert sqm literal [" + text + "] to Float",
e
);
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
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ private static boolean isTypeAssignable(
// (this list might need to be extended in future)
|| lhsJdbcType.isStringLike() && rhsJdbcType.isStringLike()
|| lhsJdbcType.isInteger() && rhsJdbcType.isInteger()
|| lhsJdbcType.isFloat() && rhsJdbcType.isFloat()
|| lhsJdbcType.isFloat() && rhsJdbcType.isInteger() ) {
|| lhsJdbcType.isFloat() && rhsJdbcType.isNumber()
|| lhsJdbcType.isDecimal() && rhsJdbcType.isNumber() ) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ public void testMathFunctions(SessionFactoryScope scope) {
// Fetching the result as float would "hide" the error as that would do some rounding
Matchers.closeTo( 9.0d, ERROR )
);
assertThat( session.createQuery("select round(32.12345,2)", Float.class).getSingleResult(), is(32.12f) );
assertThat( session.createQuery("select round(32.12345f,2)", Float.class).getSingleResult(), is(32.12f) );
assertThat( session.createQuery("select mod(3,2)", Integer.class).getSingleResult(), is(1) );
assertThat( session.createQuery("select 3%2", Integer.class).getSingleResult(), is(1) );
assertThat( session.createQuery("select sqrt(9.0)", Double.class).getSingleResult(), is(3.0d) );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.animal.Classification;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
Expand Down Expand Up @@ -60,6 +61,27 @@ public void testBinaryLiteral(SessionFactoryScope scope) {
);
}

@Test
@JiraKey("HHH-16737")
public void testUntypedIntegralLiteral(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery( "select 1 from Human h where h.bigIntegerValue = 9876543210" ).getResultList();
session.createQuery( "select 1 from Human h where h.bigIntegerValue = 98765432109876543210" ).getResultList();
}
);
}

@Test
@JiraKey("HHH-16737")
public void testUntypedDecimalLiteral(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery( "select 1 from Human h where h.bigDecimalValue = 199999.99f" ).getResultList();
}
);
}

@Test
public void testJavaString(SessionFactoryScope scope) {
scope.inTransaction(
Expand Down

0 comments on commit a209b7a

Please sign in to comment.