Florian,
I would request that you also include an update to the jdbc test suite
that tests for the case you are fixing. Other than that, the patch
looks fine. When you resubmit with the updated tests I will apply.
thanks,
--Barry
Florian Wunderlich wrote:
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)
{
------------------------------------------------------------------------
---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@xxxxxxxxxxxxxx so that your
message can get through to the mailing list cleanly
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?
http://www.postgresql.org/users-lounge/docs/faq.html