HHH-4780 - Allow BigDecimal and BigInteger to be specified as numeric literal types
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18508 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
50cbcd3e00
commit
9b3c518d5e
|
@ -598,6 +598,8 @@ literal
|
|||
| NUM_LONG { processNumericLiteral( #literal ); }
|
||||
| NUM_FLOAT { processNumericLiteral( #literal ); }
|
||||
| NUM_DOUBLE { processNumericLiteral( #literal ); }
|
||||
| NUM_BIG_INTEGER { processNumericLiteral( #literal ); }
|
||||
| NUM_BIG_DECIMAL { processNumericLiteral( #literal ); }
|
||||
| QUOTED_STRING
|
||||
;
|
||||
|
||||
|
|
|
@ -133,6 +133,8 @@ tokens
|
|||
NUM_DOUBLE;
|
||||
NUM_FLOAT;
|
||||
NUM_LONG;
|
||||
NUM_BIG_INTEGER;
|
||||
NUM_BIG_DECIMAL;
|
||||
JAVA_CONSTANT;
|
||||
}
|
||||
|
||||
|
@ -693,6 +695,8 @@ constant
|
|||
| NUM_FLOAT
|
||||
| NUM_LONG
|
||||
| NUM_DOUBLE
|
||||
| NUM_BIG_INTEGER
|
||||
| NUM_BIG_DECIMAL
|
||||
| QUOTED_STRING
|
||||
| NULL
|
||||
| TRUE
|
||||
|
@ -821,12 +825,13 @@ NUM_INT
|
|||
: '.' {_ttype = DOT;}
|
||||
( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
|
||||
{
|
||||
if (t != null && t.getText().toUpperCase().indexOf('F')>=0)
|
||||
{
|
||||
if ( t != null && t.getText().toUpperCase().indexOf("BD")>=0) {
|
||||
_ttype = NUM_BIG_DECIMAL;
|
||||
}
|
||||
else if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
|
||||
_ttype = NUM_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
_ttype = NUM_DOUBLE; // assume double
|
||||
}
|
||||
}
|
||||
|
@ -847,6 +852,7 @@ NUM_INT
|
|||
| ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
|
||||
)
|
||||
( ('l') { _ttype = NUM_LONG; }
|
||||
| ('b''i') { _ttype = NUM_BIG_INTEGER; }
|
||||
|
||||
// only check to see if it's a float if looks like decimal so far
|
||||
| {isDecimal}?
|
||||
|
@ -855,12 +861,13 @@ NUM_INT
|
|||
| f4:FLOAT_SUFFIX {t=f4;}
|
||||
)
|
||||
{
|
||||
if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0)
|
||||
{
|
||||
if ( t != null && t.getText().toUpperCase().indexOf("BD")>=0) {
|
||||
_ttype = NUM_BIG_DECIMAL;
|
||||
}
|
||||
else if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
|
||||
_ttype = NUM_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
_ttype = NUM_DOUBLE; // assume double
|
||||
}
|
||||
}
|
||||
|
@ -881,6 +888,6 @@ EXPONENT
|
|||
|
||||
protected
|
||||
FLOAT_SUFFIX
|
||||
: 'f'|'d'
|
||||
: 'f'|'d'|'b''d'
|
||||
;
|
||||
|
||||
|
|
|
@ -353,6 +353,8 @@ constant
|
|||
| NUM_FLOAT
|
||||
| NUM_INT
|
||||
| NUM_LONG
|
||||
| NUM_BIG_INTEGER
|
||||
| NUM_BIG_DECIMAL
|
||||
| QUOTED_STRING
|
||||
| CONSTANT
|
||||
| JAVA_CONSTANT
|
||||
|
|
|
@ -145,6 +145,8 @@ public class SqlASTFactory extends ASTFactory implements HqlSqlTokenTypes {
|
|||
case NUM_FLOAT:
|
||||
case NUM_LONG:
|
||||
case NUM_DOUBLE:
|
||||
case NUM_BIG_INTEGER:
|
||||
case NUM_BIG_DECIMAL:
|
||||
case QUOTED_STRING:
|
||||
return LiteralNode.class;
|
||||
case TRUE:
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hibernate.hql.ast.tree;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
@ -53,6 +52,10 @@ public class LiteralNode extends AbstractSelectExpression implements HqlSqlToken
|
|||
return Hibernate.LONG;
|
||||
case NUM_DOUBLE:
|
||||
return Hibernate.DOUBLE;
|
||||
case NUM_BIG_INTEGER:
|
||||
return Hibernate.BIG_INTEGER;
|
||||
case NUM_BIG_DECIMAL:
|
||||
return Hibernate.BIG_DECIMAL;
|
||||
case QUOTED_STRING:
|
||||
return Hibernate.STRING;
|
||||
case TRUE:
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
|
@ -229,10 +230,14 @@ public class LiteralProcessor implements HqlSqlTokenTypes {
|
|||
}
|
||||
|
||||
public void processNumeric(AST literal) {
|
||||
if ( literal.getType() == NUM_INT || literal.getType() == NUM_LONG ) {
|
||||
if ( literal.getType() == NUM_INT
|
||||
|| literal.getType() == NUM_LONG
|
||||
|| literal.getType() == NUM_BIG_INTEGER ) {
|
||||
literal.setText( determineIntegerRepresentation( literal.getText(), literal.getType() ) );
|
||||
}
|
||||
else if ( literal.getType() == NUM_FLOAT || literal.getType() == NUM_DOUBLE ) {
|
||||
else if ( literal.getType() == NUM_FLOAT
|
||||
|| literal.getType() == NUM_DOUBLE
|
||||
|| literal.getType() == NUM_BIG_DECIMAL ) {
|
||||
literal.setText( determineDecimalRepresentation( literal.getText(), literal.getType() ) );
|
||||
}
|
||||
else {
|
||||
|
@ -250,12 +255,22 @@ public class LiteralProcessor implements HqlSqlTokenTypes {
|
|||
log.trace( "could not format incoming text [" + text + "] as a NUM_INT; assuming numeric overflow and attempting as NUM_LONG" );
|
||||
}
|
||||
}
|
||||
else if ( type == NUM_LONG ) {
|
||||
String literalValue = text;
|
||||
if ( literalValue.endsWith( "l" ) || literalValue.endsWith( "L" ) ) {
|
||||
literalValue = literalValue.substring( 0, literalValue.length() - 1 );
|
||||
}
|
||||
return Long.valueOf( literalValue ).toString();
|
||||
}
|
||||
else if ( type == NUM_BIG_INTEGER ) {
|
||||
String literalValue = text;
|
||||
if ( literalValue.endsWith( "bi" ) || literalValue.endsWith( "BI" ) ) {
|
||||
literalValue = literalValue.substring( 0, literalValue.length() - 2 );
|
||||
}
|
||||
return new BigInteger( literalValue ).toString();
|
||||
}
|
||||
throw new HibernateException( "Unknown literal type to parse as integer" );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
throw new HibernateException( "Could not parse literal [" + text + "] as integer", t );
|
||||
}
|
||||
|
@ -273,6 +288,11 @@ public class LiteralProcessor implements HqlSqlTokenTypes {
|
|||
literalValue = literalValue.substring( 0, literalValue.length() - 1 );
|
||||
}
|
||||
}
|
||||
else if ( type == NUM_BIG_DECIMAL ) {
|
||||
if ( literalValue.endsWith( "bd" ) || literalValue.endsWith( "BD" ) ) {
|
||||
literalValue = literalValue.substring( 0, literalValue.length() - 2 );
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal number = null;
|
||||
try {
|
||||
|
@ -285,6 +305,7 @@ public class LiteralProcessor implements HqlSqlTokenTypes {
|
|||
return formatters[ DECIMAL_LITERAL_FORMAT ].format( number );
|
||||
}
|
||||
|
||||
|
||||
private static interface DecimalFormatter {
|
||||
String format(BigDecimal number);
|
||||
}
|
||||
|
|
|
@ -217,6 +217,11 @@ public class ValueHandlerFactory {
|
|||
}
|
||||
throw unknownConversion( value, BigInteger.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String render(BigInteger value) {
|
||||
return "cast( " + value.toString() + " as BigInteger )";
|
||||
}
|
||||
}
|
||||
|
||||
public static class BigDecimalValueHandler extends BaseValueHandler<BigDecimal> implements Serializable {
|
||||
|
@ -236,6 +241,11 @@ public class ValueHandlerFactory {
|
|||
}
|
||||
throw unknownConversion( value, BigDecimal.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String render(BigDecimal value) {
|
||||
return "cast( " + value.toString() + " as BigDecimal )";
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringValueHandler extends BaseValueHandler<String> implements Serializable {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package org.hibernate.test.hql;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Date;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
|
@ -1195,9 +1196,124 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
a.setBodyWeight(12.4f);
|
||||
a.setDescription("an animal");
|
||||
s.persist(a);
|
||||
Integer bw = (Integer) s.createQuery("select cast(bodyWeight as integer) from Animal").uniqueResult();
|
||||
bw = (Integer) s.createQuery("select cast(a.bodyWeight as integer) from Animal a").uniqueResult();
|
||||
bw.toString();
|
||||
Object bodyWeight = s.createQuery("select cast(bodyWeight as integer) from Animal").uniqueResult();
|
||||
assertTrue( Integer.class.isInstance( bodyWeight ) );
|
||||
assertEquals( 12, bodyWeight );
|
||||
bodyWeight = s.createQuery("select cast(bodyWeight as big_decimal) from Animal").uniqueResult();
|
||||
assertTrue( BigDecimal.class.isInstance( bodyWeight ) );
|
||||
assertEquals( BigDecimal.valueOf( a.getBodyWeight() ), bodyWeight );
|
||||
Object literal = s.createQuery("select cast(10000000 as big_integer) from Animal").uniqueResult();
|
||||
assertTrue( BigInteger.class.isInstance( literal ) );
|
||||
assertEquals( BigInteger.valueOf( 10000000 ), literal );
|
||||
s.delete(a);
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the numeric expression rules specified in section 4.8.6 of the JPA 2 specification
|
||||
*/
|
||||
public void testNumericExpressionReturnTypes() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Animal a = new Animal();
|
||||
a.setBodyWeight(12.4f);
|
||||
a.setDescription("an animal");
|
||||
s.persist(a);
|
||||
|
||||
Object result;
|
||||
|
||||
// addition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
result = s.createQuery( "select 1 + 1 from Animal as a" ).uniqueResult();
|
||||
assertTrue( "int + int", Integer.class.isInstance( result ) );
|
||||
assertEquals( 2, result );
|
||||
|
||||
result = s.createQuery( "select 1 + 1L from Animal a" ).uniqueResult();
|
||||
assertTrue( "int + long", Long.class.isInstance( result ) );
|
||||
assertEquals( Long.valueOf( 2 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 + 1BI from Animal a" ).uniqueResult();
|
||||
assertTrue( "int + BigInteger", BigInteger.class.isInstance( result ) );
|
||||
assertEquals( BigInteger.valueOf( 2 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 + 1F from Animal a" ).uniqueResult();
|
||||
assertTrue( "int + float", Float.class.isInstance( result ) );
|
||||
assertEquals( Float.valueOf( 2 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 + 1D from Animal a" ).uniqueResult();
|
||||
assertTrue( "int + double", Double.class.isInstance( result ) );
|
||||
assertEquals( Double.valueOf( 2 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 + 1BD from Animal a" ).uniqueResult();
|
||||
assertTrue( "int + BigDecimal", BigDecimal.class.isInstance( result ) );
|
||||
assertEquals( BigDecimal.valueOf( 2 ), result );
|
||||
|
||||
result = s.createQuery( "select 1F + 1D from Animal a" ).uniqueResult();
|
||||
assertTrue( "float + double", Double.class.isInstance( result ) );
|
||||
assertEquals( Double.valueOf( 2 ), result );
|
||||
|
||||
result = s.createQuery( "select 1F + 1BD from Animal a" ).uniqueResult();
|
||||
assertTrue( "float + BigDecimal", Float.class.isInstance( result ) );
|
||||
assertEquals( Float.valueOf( 2 ), result );
|
||||
|
||||
// subtraction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
result = s.createQuery( "select 1 - 1 from Animal as a" ).uniqueResult();
|
||||
assertTrue( "int - int", Integer.class.isInstance( result ) );
|
||||
assertEquals( 0, result );
|
||||
|
||||
result = s.createQuery( "select 1 - 1L from Animal a" ).uniqueResult();
|
||||
assertTrue( "int - long", Long.class.isInstance( result ) );
|
||||
assertEquals( Long.valueOf( 0 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 - 1BI from Animal a" ).uniqueResult();
|
||||
assertTrue( "int - BigInteger", BigInteger.class.isInstance( result ) );
|
||||
assertEquals( BigInteger.valueOf( 0 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 - 1F from Animal a" ).uniqueResult();
|
||||
assertTrue( "int - float", Float.class.isInstance( result ) );
|
||||
assertEquals( Float.valueOf( 0 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 - 1D from Animal a" ).uniqueResult();
|
||||
assertTrue( "int - double", Double.class.isInstance( result ) );
|
||||
assertEquals( Double.valueOf( 0 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 - 1BD from Animal a" ).uniqueResult();
|
||||
assertTrue( "int - BigDecimal", BigDecimal.class.isInstance( result ) );
|
||||
assertEquals( BigDecimal.valueOf( 0 ), result );
|
||||
|
||||
result = s.createQuery( "select 1F - 1D from Animal a" ).uniqueResult();
|
||||
assertTrue( "float - double", Double.class.isInstance( result ) );
|
||||
assertEquals( Double.valueOf( 0 ), result );
|
||||
|
||||
result = s.createQuery( "select 1F - 1BD from Animal a" ).uniqueResult();
|
||||
assertTrue( "float - BigDecimal", Float.class.isInstance( result ) );
|
||||
assertEquals( Float.valueOf( 0 ), result );
|
||||
|
||||
// multiplication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
result = s.createQuery( "select 1 * 1 from Animal as a" ).uniqueResult();
|
||||
assertTrue( "int * int", Integer.class.isInstance( result ) );
|
||||
assertEquals( 1, result );
|
||||
|
||||
result = s.createQuery( "select 1 * 1L from Animal a" ).uniqueResult();
|
||||
assertTrue( "int * long", Long.class.isInstance( result ) );
|
||||
assertEquals( Long.valueOf( 1 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 * 1BI from Animal a" ).uniqueResult();
|
||||
assertTrue( "int * BigInteger", BigInteger.class.isInstance( result ) );
|
||||
assertEquals( BigInteger.valueOf( 1 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 * 1F from Animal a" ).uniqueResult();
|
||||
assertTrue( "int * float", Float.class.isInstance( result ) );
|
||||
assertEquals( Float.valueOf( 1 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 * 1D from Animal a" ).uniqueResult();
|
||||
assertTrue( "int * double", Double.class.isInstance( result ) );
|
||||
assertEquals( Double.valueOf( 1 ), result );
|
||||
|
||||
result = s.createQuery( "select 1 * 1BD from Animal a" ).uniqueResult();
|
||||
assertTrue( "int * BigDecimal", BigDecimal.class.isInstance( result ) );
|
||||
assertEquals( BigDecimal.valueOf( 1 ), result );
|
||||
|
||||
s.delete(a);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
|
Loading…
Reference in New Issue