Patch from Florian Wunderlich to correctly support java Timestamps. Previously

the code would only capture milliseconds where as both postgres and the java
Timestamp object support greater resolution.
Also fixed a bug reported by Rhett Sutphin where the last digit of the
fractional seconds was lost when using timestamp without time zone

 Modified Files:
 	jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
 	jdbc/org/postgresql/test/jdbc2/TimestampTest.java
This commit is contained in:
Barry Lind 2003-01-14 09:13:51 +00:00
parent 9db065ba56
commit feefc329bd
2 changed files with 83 additions and 35 deletions

View File

@ -13,7 +13,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.7 2002/10/19 22:10:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.8 2003/01/14 09:13:51 barry Exp $
* This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2
* methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet
@ -844,7 +844,14 @@ public abstract class AbstractJdbc1ResultSet
* 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,13 @@ public abstract class AbstractJdbc1ResultSet
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 +908,36 @@ public abstract class AbstractJdbc1ResultSet
char c = s.charAt(i++);
if (c == '.')
{
// Found a fractional value. Append up to 3 digits including
// the leading '.'
do
// Found a fractional value.
final int start = i;
while (true)
{
if (i < 24)
rs.sbuf.append(c);
c = s.charAt(i++);
if (!Character.isDigit(c))
break;
if (i == slen)
{
i++;
break;
}
}
while (i < slen && Character.isDigit(c));
// 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');
}
else
{
// No fractional seconds, lets add some.
rs.sbuf.append(".000");
// The range [start, i - 1) contains all fractional digits.
final int end = i - 1;
try
{
nanos = Integer.parseInt(s.substring(start, end));
}
catch (NumberFormatException e)
{
throw new PSQLException("postgresql.unusual", e);
}
// 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 +954,7 @@ public abstract class AbstractJdbc1ResultSet
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 +963,11 @@ public abstract class AbstractJdbc1ResultSet
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");
}
}
}
@ -981,9 +1006,13 @@ public abstract class AbstractJdbc1ResultSet
{
// 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() );
org.postgresql.Driver.debug("the data after parsing is "
+ rs.sbuf.toString() + " with " + nanos + " nanos");
return new Timestamp(df.parse(rs.sbuf.toString()).getTime());
Timestamp result =
new Timestamp(df.parse(rs.sbuf.toString()).getTime());
result.setNanos(nanos);
return result;
}
catch (ParseException e)
{

View File

@ -5,7 +5,7 @@ import junit.framework.TestCase;
import java.sql.*;
/*
* $Id: TimestampTest.java,v 1.9 2002/09/06 21:23:06 momjian Exp $
* $Id: TimestampTest.java,v 1.10 2003/01/14 09:13:51 barry Exp $
*
* Test get/setTimestamp for both timestamp with time zone and
* timestamp without time zone datatypes
@ -52,11 +52,12 @@ public class TimestampTest extends TestCase
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS1WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS2WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS3WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS4WTZ_PGFORMAT + "'")));
// Fall through helper
timestampTestWTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
stmt.close();
}
@ -88,10 +89,13 @@ public class TimestampTest extends TestCase
pstmt.setTimestamp(1, TS3WTZ);
assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS4WTZ);
assertEquals(1, pstmt.executeUpdate());
// Fall through helper
timestampTestWTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
pstmt.close();
stmt.close();
@ -117,11 +121,12 @@ public class TimestampTest extends TestCase
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS1WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS2WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS3WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS4WOTZ_PGFORMAT + "'")));
// Fall through helper
timestampTestWOTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
stmt.close();
}
@ -154,10 +159,13 @@ public class TimestampTest extends TestCase
pstmt.setTimestamp(1, TS3WOTZ);
assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS4WOTZ);
assertEquals(1, pstmt.executeUpdate());
// Fall through helper
timestampTestWOTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
pstmt.close();
stmt.close();
@ -195,6 +203,11 @@ public class TimestampTest extends TestCase
assertNotNull(t);
assertTrue(t.equals(TS3WTZ));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.equals(TS4WTZ));
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
rs.close();
@ -216,17 +229,22 @@ public class TimestampTest extends TestCase
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.toString().equals(TS1WOTZ_JAVAFORMAT));
assertTrue(t.equals(TS1WOTZ));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.toString().equals(TS2WOTZ_JAVAFORMAT));
assertTrue(t.equals(TS2WOTZ));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.toString().equals(TS3WOTZ_JAVAFORMAT));
assertTrue(t.equals(TS3WOTZ));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.equals(TS4WOTZ));
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
@ -277,20 +295,21 @@ public class TimestampTest extends TestCase
private static final java.sql.Timestamp TS3WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, "GMT");
private static final String TS3WTZ_PGFORMAT = "2000-07-07 15:00:00.123+00";
private static final java.sql.Timestamp TS4WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123456000, "GMT");
private static final String TS4WTZ_PGFORMAT = "2000-07-07 15:00:00.123456+00";
private static final java.sql.Timestamp TS1WOTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, null);
private static final String TS1WOTZ_PGFORMAT = "1950-02-07 15:00:00.1";
private static final String TS1WOTZ_JAVAFORMAT = "1950-02-07 15:00:00.1";
private static final java.sql.Timestamp TS2WOTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, null);
private static final String TS2WOTZ_PGFORMAT = "2000-02-07 15:00:00.12";
//there is probably a bug here in that this needs to be .1 instead of .12, but I couldn't find it now
private static final String TS2WOTZ_JAVAFORMAT = "2000-02-07 15:00:00.1";
private static final java.sql.Timestamp TS3WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, null);
private static final String TS3WOTZ_PGFORMAT = "2000-07-07 15:00:00.123";
//there is probably a bug here in that this needs to be .12 instead of .123, but I couldn't find it now
private static final String TS3WOTZ_JAVAFORMAT = "2000-07-07 15:00:00.12";
private static final java.sql.Timestamp TS4WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123456000, null);
private static final String TS4WOTZ_PGFORMAT = "2000-07-07 15:00:00.123456";
private static final String TSWTZ_TABLE = "testtimestampwtz";
private static final String TSWOTZ_TABLE = "testtimestampwotz";