[hibernate-commits] Hibernate SVN: r18508 - in core/trunk: core/src/main/java/org/hibernate/hql/ast and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Jan 11 17:55:37 EST 2010


Author: steve.ebersole at jboss.com
Date: 2010-01-11 17:55:36 -0500 (Mon, 11 Jan 2010)
New Revision: 18508

Modified:
   core/trunk/core/src/main/antlr/hql-sql.g
   core/trunk/core/src/main/antlr/hql.g
   core/trunk/core/src/main/antlr/sql-gen.g
   core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java
   core/trunk/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/ValueHandlerFactory.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
Log:
HHH-4780 - Allow BigDecimal and BigInteger to be specified as numeric literal types


Modified: core/trunk/core/src/main/antlr/hql-sql.g
===================================================================
--- core/trunk/core/src/main/antlr/hql-sql.g	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/core/src/main/antlr/hql-sql.g	2010-01-11 22:55:36 UTC (rev 18508)
@@ -598,6 +598,8 @@
 	| NUM_LONG { processNumericLiteral( #literal ); }
 	| NUM_FLOAT { processNumericLiteral( #literal ); }
 	| NUM_DOUBLE { processNumericLiteral( #literal ); }
+	| NUM_BIG_INTEGER { processNumericLiteral( #literal ); }
+	| NUM_BIG_DECIMAL { processNumericLiteral( #literal ); }
 	| QUOTED_STRING
 	;
 

Modified: core/trunk/core/src/main/antlr/hql.g
===================================================================
--- core/trunk/core/src/main/antlr/hql.g	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/core/src/main/antlr/hql.g	2010-01-11 22:55:36 UTC (rev 18508)
@@ -133,6 +133,8 @@
 	NUM_DOUBLE;
 	NUM_FLOAT;
 	NUM_LONG;
+	NUM_BIG_INTEGER;
+	NUM_BIG_DECIMAL;
 	JAVA_CONSTANT;
 }
 
@@ -693,6 +695,8 @@
 	| NUM_FLOAT
 	| NUM_LONG
 	| NUM_DOUBLE
+	| NUM_BIG_INTEGER
+	| NUM_BIG_DECIMAL
 	| QUOTED_STRING
 	| NULL
 	| TRUE
@@ -821,12 +825,13 @@
 	:   '.' {_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 @@
 		|	('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 @@
 			|   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 @@
 
 protected
 FLOAT_SUFFIX
-	:	'f'|'d'
+	:	'f'|'d'|'b''d'
 	;
 

Modified: core/trunk/core/src/main/antlr/sql-gen.g
===================================================================
--- core/trunk/core/src/main/antlr/sql-gen.g	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/core/src/main/antlr/sql-gen.g	2010-01-11 22:55:36 UTC (rev 18508)
@@ -353,6 +353,8 @@
 	| NUM_FLOAT
 	| NUM_INT
 	| NUM_LONG
+	| NUM_BIG_INTEGER
+	| NUM_BIG_DECIMAL
 	| QUOTED_STRING
 	| CONSTANT
 	| JAVA_CONSTANT

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java	2010-01-11 22:55:36 UTC (rev 18508)
@@ -145,6 +145,8 @@
 			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:

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java	2010-01-11 22:55:36 UTC (rev 18508)
@@ -22,7 +22,6 @@
  * Boston, MA  02110-1301  USA
  *
  */
-
 package org.hibernate.hql.ast.tree;
 
 import org.hibernate.Hibernate;
@@ -53,6 +52,10 @@
 				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:

Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java	2010-01-11 22:55:36 UTC (rev 18508)
@@ -50,6 +50,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.text.DecimalFormat;
 
 /**
@@ -229,10 +230,14 @@
 	}
 
 	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,11 +255,21 @@
 					log.trace( "could not format incoming text [" + text + "] as a NUM_INT; assuming numeric overflow and attempting as NUM_LONG" );
 				}
 			}
-			String literalValue = text;
-			if ( literalValue.endsWith( "l" ) || literalValue.endsWith( "L" ) ) {
-				literalValue = literalValue.substring( 0, literalValue.length() - 1 );
+			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();
 			}
-			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 @@
 				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 @@
 		return formatters[ DECIMAL_LITERAL_FORMAT ].format( number );
 	}
 
+
 	private static interface DecimalFormatter {
 		String format(BigDecimal number);
 	}

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/ValueHandlerFactory.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/ValueHandlerFactory.java	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/ValueHandlerFactory.java	2010-01-11 22:55:36 UTC (rev 18508)
@@ -217,6 +217,11 @@
 			}
 			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 @@
 			}
 			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 {

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java	2010-01-11 20:27:12 UTC (rev 18507)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java	2010-01-11 22:55:36 UTC (rev 18508)
@@ -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,14 +1196,129 @@
 		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();
+	}
+
 	public void testAliases() {
 		Session s = openSession();
 		Transaction t = s.beginTransaction();



More information about the hibernate-commits mailing list