提交 feefc329 编写于 作者: B Barry Lind

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
上级 9db065ba
......@@ -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)
{
......
......@@ -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";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册