提交 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.*; ...@@ -13,7 +13,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea; import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException; 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 * This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2 * extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2
* methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet * methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet
...@@ -844,7 +844,14 @@ public abstract class AbstractJdbc1ResultSet ...@@ -844,7 +844,14 @@ public abstract class AbstractJdbc1ResultSet
* Java also expects fractional seconds to 3 places where postgres * Java also expects fractional seconds to 3 places where postgres
* will give, none, 2 or 6 depending on the time and postgres version. * will give, none, 2 or 6 depending on the time and postgres version.
* From version 7.2 postgres returns fractional seconds to 6 places. * 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 s The ISO formated date string to parse.
* @param resultSet The ResultSet this date is part of. * @param resultSet The ResultSet this date is part of.
...@@ -881,6 +888,13 @@ public abstract class AbstractJdbc1ResultSet ...@@ -881,6 +888,13 @@ public abstract class AbstractJdbc1ResultSet
rs.sbuf.append(s); rs.sbuf.append(s);
int slen = s.length(); 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) if (slen > 19)
{ {
// The len of the ISO string to the second value is 19 chars. If // The len of the ISO string to the second value is 19 chars. If
...@@ -894,25 +908,36 @@ public abstract class AbstractJdbc1ResultSet ...@@ -894,25 +908,36 @@ public abstract class AbstractJdbc1ResultSet
char c = s.charAt(i++); char c = s.charAt(i++);
if (c == '.') if (c == '.')
{ {
// Found a fractional value. Append up to 3 digits including // Found a fractional value.
// the leading '.' final int start = i;
do while (true)
{ {
if (i < 24)
rs.sbuf.append(c);
c = s.charAt(i++); 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 // The range [start, i - 1) contains all fractional digits.
// to make up the 3 digits we tell java to expect. final int end = i - 1;
for (int j = i; j < 24; j++) try
rs.sbuf.append('0'); {
} nanos = Integer.parseInt(s.substring(start, end));
else }
{ catch (NumberFormatException e)
// No fractional seconds, lets add some. {
rs.sbuf.append(".000"); 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) if (i < slen)
...@@ -929,7 +954,7 @@ public abstract class AbstractJdbc1ResultSet ...@@ -929,7 +954,7 @@ public abstract class AbstractJdbc1ResultSet
rs.sbuf.append(":00"); rs.sbuf.append(":00");
// we'll use this dateformat string to parse the result. // 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 else
{ {
...@@ -938,11 +963,11 @@ public abstract class AbstractJdbc1ResultSet ...@@ -938,11 +963,11 @@ public abstract class AbstractJdbc1ResultSet
if (pgDataType.equals("timestamptz")) if (pgDataType.equals("timestamptz"))
{ {
rs.sbuf.append(" GMT"); 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 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 ...@@ -981,9 +1006,13 @@ public abstract class AbstractJdbc1ResultSet
{ {
// All that's left is to parse the string and return the ts. // All that's left is to parse the string and return the ts.
if ( org.postgresql.Driver.logDebug ) 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) catch (ParseException e)
{ {
......
...@@ -5,7 +5,7 @@ import junit.framework.TestCase; ...@@ -5,7 +5,7 @@ import junit.framework.TestCase;
import java.sql.*; 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 * Test get/setTimestamp for both timestamp with time zone and
* timestamp without time zone datatypes * timestamp without time zone datatypes
...@@ -52,11 +52,12 @@ public class TimestampTest extends TestCase ...@@ -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, "'" + TS1WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS2WTZ_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, "'" + TS3WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS4WTZ_PGFORMAT + "'")));
// Fall through helper // Fall through helper
timestampTestWTZ(); timestampTestWTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE)); assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
stmt.close(); stmt.close();
} }
...@@ -88,10 +89,13 @@ public class TimestampTest extends TestCase ...@@ -88,10 +89,13 @@ public class TimestampTest extends TestCase
pstmt.setTimestamp(1, TS3WTZ); pstmt.setTimestamp(1, TS3WTZ);
assertEquals(1, pstmt.executeUpdate()); assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS4WTZ);
assertEquals(1, pstmt.executeUpdate());
// Fall through helper // Fall through helper
timestampTestWTZ(); timestampTestWTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE)); assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
pstmt.close(); pstmt.close();
stmt.close(); stmt.close();
...@@ -117,11 +121,12 @@ public class TimestampTest extends TestCase ...@@ -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, "'" + TS1WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS2WOTZ_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, "'" + TS3WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS4WOTZ_PGFORMAT + "'")));
// Fall through helper // Fall through helper
timestampTestWOTZ(); timestampTestWOTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE)); assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
stmt.close(); stmt.close();
} }
...@@ -154,10 +159,13 @@ public class TimestampTest extends TestCase ...@@ -154,10 +159,13 @@ public class TimestampTest extends TestCase
pstmt.setTimestamp(1, TS3WOTZ); pstmt.setTimestamp(1, TS3WOTZ);
assertEquals(1, pstmt.executeUpdate()); assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS4WOTZ);
assertEquals(1, pstmt.executeUpdate());
// Fall through helper // Fall through helper
timestampTestWOTZ(); timestampTestWOTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE)); assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
pstmt.close(); pstmt.close();
stmt.close(); stmt.close();
...@@ -195,6 +203,11 @@ public class TimestampTest extends TestCase ...@@ -195,6 +203,11 @@ public class TimestampTest extends TestCase
assertNotNull(t); assertNotNull(t);
assertTrue(t.equals(TS3WTZ)); 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. assertTrue(! rs.next()); // end of table. Fail if more entries exist.
rs.close(); rs.close();
...@@ -216,17 +229,22 @@ public class TimestampTest extends TestCase ...@@ -216,17 +229,22 @@ public class TimestampTest extends TestCase
assertTrue(rs.next()); assertTrue(rs.next());
t = rs.getTimestamp(1); t = rs.getTimestamp(1);
assertNotNull(t); assertNotNull(t);
assertTrue(t.toString().equals(TS1WOTZ_JAVAFORMAT)); assertTrue(t.equals(TS1WOTZ));
assertTrue(rs.next()); assertTrue(rs.next());
t = rs.getTimestamp(1); t = rs.getTimestamp(1);
assertNotNull(t); assertNotNull(t);
assertTrue(t.toString().equals(TS2WOTZ_JAVAFORMAT)); assertTrue(t.equals(TS2WOTZ));
assertTrue(rs.next()); assertTrue(rs.next());
t = rs.getTimestamp(1); t = rs.getTimestamp(1);
assertNotNull(t); 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. assertTrue(! rs.next()); // end of table. Fail if more entries exist.
...@@ -277,20 +295,21 @@ public class TimestampTest extends TestCase ...@@ -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 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 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 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_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 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"; 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 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"; 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 TSWTZ_TABLE = "testtimestampwtz";
private static final String TSWOTZ_TABLE = "testtimestampwotz"; private static final String TSWOTZ_TABLE = "testtimestampwotz";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册