toTimestamp fractional seconds fix (patch against CVS)

Поиск
Список
Период
Сортировка
От Florian Wunderlich
Тема toTimestamp fractional seconds fix (patch against CVS)
Дата
Msg-id 3E070A04.BB0EC23C@hq.factor3.com
обсуждение исходный текст
Ответы Re: toTimestamp fractional seconds fix (patch against CVS)  (Barry Lind <blind@xythos.com>)
Список pgsql-jdbc
In the CVS, in AbstractJdbc1ResultSet.java, a Timestamp returned from
toTimestamp is created with DateFormat.parse, which means that
fractional milliseconds are dropped - no more than 3 fractional digits
are considered.

1. This means that the JDBC driver returns values that are not in the
database. A subsequent query specifying this value in a WHERE clause for
example will not return the record in question.

2. java.sql.Timestamp specifies that all fractional seconds are to be
stored in the nanos field, and that the getTime method shall return only
integral seconds.

The attached patch against the most recent version from the CVS as of
2002-12-23 14:02 (rev 1.7) fixes this behavior. I have verified it
against postgresql-7.2.1.Index: AbstractJdbc1ResultSet.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java,v
retrieving revision 1.7
diff -u -b -r1.7 AbstractJdbc1ResultSet.java
--- AbstractJdbc1ResultSet.java    2002/10/19 22:10:36    1.7
+++ AbstractJdbc1ResultSet.java    2002/12/23 12:49:34
@@ -844,8 +844,15 @@
     * Java also expects fractional seconds to 3 places where postgres
     * will give, none, 2 or 6 depending on the time and postgres version.
     * From version 7.2 postgres returns fractional seconds to 6 places.
-    * If available, we drop the last 3 digits.
     *
+        * According to the Timestamp documentation, fractional digits are kept
+        * in the nanos field of Timestamp and not in the milliseconds of Date.
+        * Thus, parsing for fractional digits is entirely separated from the
+        * rest.
+        *
+        * The method assumes that there are no more than 9 fractional
+        * digits given. Undefined behavior if this is not the case.
+    *
     * @param s           The ISO formated date string to parse.
     * @param resultSet The ResultSet this date is part of.
     *
@@ -881,6 +888,18 @@
             rs.sbuf.append(s);
             int slen = s.length();

+
+                        //
+                        // For a Timestamp, the fractional seconds are stored in the
+                        // nanos field. As a DateFormat is used for parsing which can
+                        // only parse to millisecond precision and which returns a
+                        // Date object, the fractional second parsing is completely
+                        // separate.
+                        //
+
+                        int nanos = 0;
+
+
             if (slen > 19)
             {
                 // The len of the ISO string to the second value is 19 chars. If
@@ -894,25 +913,42 @@
                 char c = s.charAt(i++);
                 if (c == '.')
                 {
-                    // Found a fractional value. Append up to 3 digits including
-                    // the leading '.'
+                                        // Found a fractional value.
+
+                                        final int start = i;
+
                     do
                     {
-                        if (i < 24)
-                            rs.sbuf.append(c);
                         c = s.charAt(i++);
                     }
                     while (i < slen && Character.isDigit(c));
+
+
+                                        //
+                                        // The range [start, i - 1) contains all fractional digits.
+                                        //
+
+                                        final int end = i - 1;

-                    // If there wasn't at least 3 digits we should add some zeros
-                    // to make up the 3 digits we tell java to expect.
-                    for (int j = i; j < 24; j++)
-                        rs.sbuf.append('0');
+                                        try
+                                        {
+                                          nanos = Integer.parseInt(s.substring(start, end));
                 }
-                else
+                                        catch (NumberFormatException e)
                 {
-                    // No fractional seconds, lets add some.
-                    rs.sbuf.append(".000");
+                                          // this Exception can never happen, as the range has
+                                          // been checked before.
+                                        }
+
+
+                                        //
+                                        // The nanos field stores nanoseconds. Adjust the parsed
+                                        // value to the correct magnitude.
+                                        //
+
+                                        for (int digitsToNano = 9 - (end - start);
+                                             digitsToNano > 0; --digitsToNano)
+                                          nanos *= 10;
                 }

                 if (i < slen)
@@ -929,7 +965,7 @@
                         rs.sbuf.append(":00");

                     // we'll use this dateformat string to parse the result.
-                    df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
+                    df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
                 }
                 else
                 {
@@ -938,11 +974,11 @@
                     if (pgDataType.equals("timestamptz"))
                     {
                         rs.sbuf.append(" GMT");
-                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
+                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
                     }
                     else
                     {
-                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                     }
                 }
             }
@@ -982,8 +1018,13 @@
                 // All that's left is to parse the string and return the ts.
                 if ( org.postgresql.Driver.logDebug )
                     org.postgresql.Driver.debug( "" + df.parse(rs.sbuf.toString()).getTime() );
+
+                                final Timestamp result =
+                                  new Timestamp(df.parse(rs.sbuf.toString()).getTime());
+
+                                result.setNanos(nanos);

-                return new Timestamp(df.parse(rs.sbuf.toString()).getTime());
+                                return result;
             }
             catch (ParseException e)
             {

В списке pgsql-jdbc по дате отправления:

Предыдущее
От: Daniel Serodio
Дата:
Сообщение: Re: JDBC Error
Следующее
От: "Remigius Stalder"
Дата:
Сообщение: Re: Stored procedures/functions that can return recordsets...