You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by jg...@apache.org on 2014/02/03 23:41:12 UTC

svn commit: r1564121 - in /openjpa/branches/2.3.x: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/temporal/ openjpa-project/src/doc/manual/

Author: jgrassel
Date: Mon Feb  3 22:41:12 2014
New Revision: 1564121

URL: http://svn.apache.org/r1564121
Log:
OPENJPA-2453: Add support to retain milliseconds of 'un-rounded' Date field.

Modified:
    openjpa/branches/2.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/branches/2.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/temporal/TestTemporalTimestamp.java
    openjpa/branches/2.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml

Modified: openjpa/branches/2.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1564121&r1=1564120&r2=1564121&view=diff
==============================================================================
--- openjpa/branches/2.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/branches/2.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Mon Feb  3 22:41:12 2014
@@ -300,7 +300,31 @@ public class DBDictionary
     public int maxEmbeddedClobSize = -1;
     public int inClauseLimit = -1;
     public int datePrecision = MILLI;
+       
+    /**
+     * @deprecated Use 'dateMillisecondBehavior' instead.
+     */
+    @Deprecated
     public boolean roundTimeToMillisec = true;
+
+    /*
+     * This defines how the milliseconds of a Date field are handled 
+     * when the Date is retrieved from the database, as follows:
+     * 
+     * ROUND: This is the default.  The 
+     * Date will be rounded to the nearest millisecond. 
+     * DROP: The milliseconds will be dropped, thus rounding is not 
+     * performed.  As an example, a date of '2010-01-01 12:00:00.687701' 
+     * stored in the database will become '2010-01-01 12:00:00.000' in 
+     * the Date field of the entity.
+     * RETAIN: The milliseconds will not be rounded and retained.  As an 
+     * example, a date of '2010-01-01 12:00:00.687701' stored in the
+     * database will become '2010-01-01 12:00:00.687' in the Date field 
+     * of the entity.
+     */
+    public enum DateMillisecondBehaviors { DROP, ROUND, RETAIN };    
+    private DateMillisecondBehaviors dateMillisecondBehavior;
+    
     public int characterColumnSize = 255;
     public String arrayTypeName = "ARRAY";
     public String bigintTypeName = "BIGINT";
@@ -792,8 +816,16 @@ public class DBDictionary
         // get the fractional seconds component, rounding away anything beyond
         // milliseconds
         int fractional = 0;
-        if (roundTimeToMillisec) {
-            fractional = (int) Math.round(tstamp.getNanos() / (double) MILLI);
+        switch (getMillisecondBehavior()) {
+            case DROP :
+                fractional = 0;
+                break;
+            case RETAIN :
+                fractional = (int) (tstamp.getNanos() / (double) MILLI);
+                break;
+            case ROUND :
+                fractional = (int) Math.round(tstamp.getNanos() / (double) MILLI);
+                break;
         }
 
         // get the millis component; some JDBC drivers round this to the
@@ -5621,6 +5653,33 @@ public class DBDictionary
     
     public String getIdentityColumnName() {
         return null;       
+    }    
+    
+    /**
+     * Default behavior is ROUND
+     */
+    public DateMillisecondBehaviors getMillisecondBehavior() {
+        // If the user hasn't configured this property, fall back 
+        // to looking at the old property in the mean time till 
+        // we can get rid of it.
+        if (dateMillisecondBehavior == null) {
+            if (roundTimeToMillisec) {
+                dateMillisecondBehavior = DateMillisecondBehaviors.ROUND;
+            } else {
+                dateMillisecondBehavior = DateMillisecondBehaviors.DROP;
+            }
+        }
+        return dateMillisecondBehavior;
+    }
+ 
+    public void setDateMillisecondBehavior(String str) {
+        if (str != null) {
+            // Tolerate different case
+            str = str.toUpperCase();
+            dateMillisecondBehavior = DateMillisecondBehaviors.valueOf(str);
+        } else {
+            dateMillisecondBehavior = null;
+        }
     }
 
 	protected boolean isUsingRange(long start, long end) {

Modified: openjpa/branches/2.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/temporal/TestTemporalTimestamp.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/temporal/TestTemporalTimestamp.java?rev=1564121&r1=1564120&r2=1564121&view=diff
==============================================================================
--- openjpa/branches/2.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/temporal/TestTemporalTimestamp.java (original)
+++ openjpa/branches/2.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/temporal/TestTemporalTimestamp.java Mon Feb  3 22:41:12 2014
@@ -18,6 +18,7 @@
  */
 package org.apache.openjpa.persistence.temporal;
 
+import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
 
@@ -31,8 +32,8 @@ import org.apache.openjpa.persistence.Op
 import org.apache.openjpa.persistence.test.SQLListenerTestCase;
 
 public class TestTemporalTimestamp extends SQLListenerTestCase {
-    private OpenJPAEntityManager em;
-    
+    private OpenJPAEntityManager em;    
+    final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
     
     public void setUp() {
         setSupportedDatabases(
@@ -42,8 +43,34 @@ public class TestTemporalTimestamp exten
             return;
         }
         
-        setUp(CLEAR_TABLES, TemporalEntity.class, "openjpa.jdbc.DBDictionary", "RoundTimeToMillisec=false");
+        setUp(CLEAR_TABLES, TemporalEntity.class, "openjpa.jdbc.DBDictionary", 
+            "DateMillisecondBehavior=" + DBDictionary.DateMillisecondBehaviors.DROP,
+            "openjpa.Log", "SQL=TRACE,Tests=TRACE", "openjpa.ConnectionFactoryProperties"
+            ,"PrintParameters=true");
         assertNotNull(emf);
+//        noRound:
+  //      expected:<253402322399000> but was:<253402325999000>
+/*        Date got = new Date(253402322399000L);
+        Date exp = new Date(253402325999000L);        
+        System.out.println("NoRounding");
+        System.out.println("Got = " + sdf.format(got).toString());
+        System.out.println("Exp = " + sdf.format(exp).toString());
+*/
+        //testNoRoundingNoMillisecondLoss
+        //expected:<253402322399999> but was:<253402325999999>
+/*        got = new Date(253402322399999L);
+        exp = new Date(253402325999999L);        
+        System.out.println("testNoRoundingNoMillisecondLoss");
+        System.out.println("Got = " + sdf.format(got).toString());
+        System.out.println("Exp = " + sdf.format(exp).toString());
+        */
+        //expected:<253402322400000> but was:<253402326000000>
+/*        got = new Date(253402322400000L);
+        exp = new Date(253402326000000L);        
+        System.out.println("testRounding");
+        System.out.println("Got = " + sdf.format(got).toString());
+        System.out.println("Exp = " + sdf.format(exp).toString());
+  */      
         
         loadDB();
     }
@@ -62,6 +89,32 @@ public class TestTemporalTimestamp exten
             assertEquals(testDate.getMinutes(), 59);
             assertEquals(testDate.getSeconds(), 59);
             assertEquals(testDate.getYear(), 8099);
+            assertTrue(sdf.format(testDate).toString().endsWith(".000"));
+        }
+        em.close();
+    }
+
+    public void testNoRoundingNoMillisecondLoss() {
+        JDBCConfiguration conf = (JDBCConfiguration) emf.getConfiguration();
+        DBDictionary dict = conf.getDBDictionaryInstance();
+        dict.setDateMillisecondBehavior(DBDictionary.DateMillisecondBehaviors.RETAIN.toString());
+        
+        em = emf.createEntityManager();
+        final List<TemporalEntity> temporalEntityList = findAll(em);
+        assertNotNull(temporalEntityList);
+        assertNotEquals(temporalEntityList.size(), 0);
+        for (final TemporalEntity temporalEntity : temporalEntityList) {
+            Date testDate = temporalEntity.getTestDate();
+            assertEquals(testDate.getDay(), 5);
+            assertEquals(testDate.getMonth(), 11);
+            assertEquals(testDate.getDate(), 31);
+            assertEquals(testDate.getHours(), 23);
+            assertEquals(testDate.getMinutes(), 59);
+            assertEquals(testDate.getSeconds(), 59);
+            assertEquals(testDate.getYear(), 8099);
+            assertTrue(sdf.format(testDate).toString().endsWith(".999"));            
+            System.out.println("sdf.format(testDate).toString() = " +
+                sdf.format(testDate).toString());
         }
         em.close();
     }
@@ -70,7 +123,7 @@ public class TestTemporalTimestamp exten
         JDBCConfiguration conf = (JDBCConfiguration) emf.getConfiguration();
         DBDictionary dict = conf.getDBDictionaryInstance();
         // set value back to default
-        dict.roundTimeToMillisec = true;
+        dict.setDateMillisecondBehavior(DBDictionary.DateMillisecondBehaviors.ROUND.toString());
         
         em = emf.createEntityManager();
         final List<TemporalEntity> temporalEntityList = findAll(em);
@@ -85,6 +138,8 @@ public class TestTemporalTimestamp exten
             assertEquals(testDate.getMinutes(), 0);
             assertEquals(testDate.getSeconds(), 0);
             assertEquals(testDate.getYear(), 8100);
+//            assertEquals(testDate.getTime(), 253402326000000L);
+            assertTrue(sdf.format(testDate).toString().endsWith(".000"));
         }
         em.close();
     }

Modified: openjpa/branches/2.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml
URL: http://svn.apache.org/viewvc/openjpa/branches/2.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml?rev=1564121&r1=1564120&r2=1564121&view=diff
==============================================================================
--- openjpa/branches/2.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml (original)
+++ openjpa/branches/2.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml Mon Feb  3 22:41:12 2014
@@ -1409,6 +1409,53 @@ before storing them in the database.
 Defaults to 1000000.
                     </para>
                 </listitem>
+                <listitem id="DBDictionary.DateMillisecondBehavior">
+                    <para>
+                    <indexterm>
+                        <primary>
+                            JDBC
+                        </primary>
+                        <secondary>
+                            DateMillisecondBehavior
+                        </secondary>
+                    </indexterm>
+<literal>DateMillisecondBehavior</literal>:
+When retrieving a <literal>Date</literal> value from a database which stores the value in 
+a TIMESTAMP column, the values retrieved will be rounded to the nearest
+millisecond.  So a date of '2010-01-01 12:00:00.687701' stored in the
+database will become '2010-01-01 12:00:00.688' in the <literal>Date</literal> field of the
+entity.  The following date stored in the database as '9999-12-31 23:59:59.9999' 
+will become '10000-01-01 00:00:00.000'.  This rounding may not be desirable.  With this
+property, a user has options which will direct OpenJPA how to handle the milliseconds.  This 
+property can be set to one of the enums defined in 
+<literal>DBDictionary.DateMillisecondBehaviors</literal>.  The options defined in 
+<literal>DBDictionary.DateMillisecondBehaviors</literal> are as follows:
+                <itemizedlist>
+                    <listitem>
+                        <para>
+<literal>DateMillisecondBehaviors.ROUND</literal>: This is the default.  The 
+<literal>Date</literal> will be rounded to the nearest millisecond, as described above.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+<literal>DateMillisecondBehaviors.DROP</literal>: The milliseconds will be dropped, thus
+rounding is not performed.  As an example, a date of '2010-01-01 12:00:00.687701' stored in the
+database will become '2010-01-01 12:00:00.000' in the <literal>Date</literal> field of the
+entity.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+<literal>DateMillisecondBehaviors.RETAIN</literal>: The milliseconds will not be rounded, but will
+be retained.  As an example, a date of '2010-01-01 12:00:00.687701' stored in the
+database will become '2010-01-01 12:00:00.687' in the <literal>Date</literal> field of the
+entity.  
+                        </para>
+                    </listitem>
+                </itemizedlist>
+                    </para>
+                </listitem>                
                 <listitem id="DBDictionary.DateTypeName">
                     <para>
                     <indexterm>