Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit feefc32

Browse files
author
Barry Lind
committed
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
1 parent 9db065b commit feefc32

File tree

2 files changed

+83
-35
lines changed

2 files changed

+83
-35
lines changed

src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import org.postgresql.util.PGbytea;
1414
import org.postgresql.util.PSQLException;
1515

16-
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.7 2002/10/19 22:10:36 barry Exp $
16+
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.8 2003/01/14 09:13:51 barry Exp $
1717
* This class defines methods of the jdbc1 specification. This class is
1818
* extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2
1919
* methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet
@@ -844,7 +844,14 @@ else if (l_millis < 100)
844844
* Java also expects fractional seconds to 3 places where postgres
845845
* will give, none, 2 or 6 depending on the time and postgres version.
846846
* From version 7.2 postgres returns fractional seconds to 6 places.
847-
* If available, we drop the last 3 digits.
847+
*
848+
* According to the Timestamp documentation, fractional digits are kept
849+
* in the nanos field of Timestamp and not in the milliseconds of Date.
850+
* Thus, parsing for fractional digits is entirely separated from the
851+
* rest.
852+
*
853+
* The method assumes that there are no more than 9 fractional
854+
* digits given. Undefined behavior if this is not the case.
848855
*
849856
* @param s The ISO formated date string to parse.
850857
* @param resultSet The ResultSet this date is part of.
@@ -881,6 +888,13 @@ public static Timestamp toTimestamp(String s, java.sql.ResultSet resultSet, Stri
881888
rs.sbuf.append(s);
882889
int slen = s.length();
883890

891+
// For a Timestamp, the fractional seconds are stored in the
892+
// nanos field. As a DateFormat is used for parsing which can
893+
// only parse to millisecond precision and which returns a
894+
// Date object, the fractional second parsing is completely
895+
// separate.
896+
int nanos = 0;
897+
884898
if (slen > 19)
885899
{
886900
// The len of the ISO string to the second value is 19 chars. If
@@ -894,25 +908,36 @@ public static Timestamp toTimestamp(String s, java.sql.ResultSet resultSet, Stri
894908
char c = s.charAt(i++);
895909
if (c == '.')
896910
{
897-
// Found a fractional value. Append up to 3 digits including
898-
// the leading '.'
899-
do
911+
// Found a fractional value.
912+
final int start = i;
913+
while (true)
900914
{
901-
if (i < 24)
902-
rs.sbuf.append(c);
903915
c = s.charAt(i++);
916+
if (!Character.isDigit(c))
917+
break;
918+
if (i == slen)
919+
{
920+
i++;
921+
break;
922+
}
904923
}
905-
while (i < slen && Character.isDigit(c));
906924

907-
// If there wasn't at least 3 digits we should add some zeros
908-
// to make up the 3 digits we tell java to expect.
909-
for (int j = i; j < 24; j++)
910-
rs.sbuf.append('0');
911-
}
912-
else
913-
{
914-
// No fractional seconds, lets add some.
915-
rs.sbuf.append(".000");
925+
// The range [start, i - 1) contains all fractional digits.
926+
final int end = i - 1;
927+
try
928+
{
929+
nanos = Integer.parseInt(s.substring(start, end));
930+
}
931+
catch (NumberFormatException e)
932+
{
933+
throw new PSQLException("postgresql.unusual", e);
934+
}
935+
936+
// The nanos field stores nanoseconds. Adjust the parsed
937+
// value to the correct magnitude.
938+
for (int digitsToNano = 9 - (end - start);
939+
digitsToNano > 0; --digitsToNano)
940+
nanos *= 10;
916941
}
917942

918943
if (i < slen)
@@ -929,7 +954,7 @@ public static Timestamp toTimestamp(String s, java.sql.ResultSet resultSet, Stri
929954
rs.sbuf.append(":00");
930955

931956
// we'll use this dateformat string to parse the result.
932-
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
957+
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
933958
}
934959
else
935960
{
@@ -938,11 +963,11 @@ public static Timestamp toTimestamp(String s, java.sql.ResultSet resultSet, Stri
938963
if (pgDataType.equals("timestamptz"))
939964
{
940965
rs.sbuf.append(" GMT");
941-
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
966+
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
942967
}
943968
else
944969
{
945-
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
970+
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
946971
}
947972
}
948973
}
@@ -981,9 +1006,13 @@ else if (slen == 19)
9811006
{
9821007
// All that's left is to parse the string and return the ts.
9831008
if ( org.postgresql.Driver.logDebug )
984-
org.postgresql.Driver.debug( "" + df.parse(rs.sbuf.toString()).getTime() );
1009+
org.postgresql.Driver.debug("the data after parsing is "
1010+
+ rs.sbuf.toString() + " with " + nanos + " nanos");
9851011

986-
return new Timestamp(df.parse(rs.sbuf.toString()).getTime());
1012+
Timestamp result =
1013+
new Timestamp(df.parse(rs.sbuf.toString()).getTime());
1014+
result.setNanos(nanos);
1015+
return result;
9871016
}
9881017
catch (ParseException e)
9891018
{

src/interfaces/jdbc/org/postgresql/test/jdbc2/TimestampTest.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import java.sql.*;
66

77
/*
8-
* $Id: TimestampTest.java,v 1.9 2002/09/06 21:23:06 momjian Exp $
8+
* $Id: TimestampTest.java,v 1.10 2003/01/14 09:13:51 barry Exp $
99
*
1010
* Test get/setTimestamp for both timestamp with time zone and
1111
* timestamp without time zone datatypes
@@ -52,11 +52,12 @@ public void testGetTimestampWTZ()
5252
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS1WTZ_PGFORMAT + "'")));
5353
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS2WTZ_PGFORMAT + "'")));
5454
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS3WTZ_PGFORMAT + "'")));
55+
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS4WTZ_PGFORMAT + "'")));
5556

5657
// Fall through helper
5758
timestampTestWTZ();
5859

59-
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
60+
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
6061

6162
stmt.close();
6263
}
@@ -88,10 +89,13 @@ public void testSetTimestampWTZ()
8889
pstmt.setTimestamp(1, TS3WTZ);
8990
assertEquals(1, pstmt.executeUpdate());
9091

92+
pstmt.setTimestamp(1, TS4WTZ);
93+
assertEquals(1, pstmt.executeUpdate());
94+
9195
// Fall through helper
9296
timestampTestWTZ();
9397

94-
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
98+
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
9599

96100
pstmt.close();
97101
stmt.close();
@@ -117,11 +121,12 @@ public void testGetTimestampWOTZ()
117121
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS1WOTZ_PGFORMAT + "'")));
118122
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS2WOTZ_PGFORMAT + "'")));
119123
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS3WOTZ_PGFORMAT + "'")));
124+
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS4WOTZ_PGFORMAT + "'")));
120125

121126
// Fall through helper
122127
timestampTestWOTZ();
123128

124-
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
129+
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
125130

126131
stmt.close();
127132
}
@@ -154,10 +159,13 @@ public void testSetTimestampWOTZ()
154159
pstmt.setTimestamp(1, TS3WOTZ);
155160
assertEquals(1, pstmt.executeUpdate());
156161

162+
pstmt.setTimestamp(1, TS4WOTZ);
163+
assertEquals(1, pstmt.executeUpdate());
164+
157165
// Fall through helper
158166
timestampTestWOTZ();
159167

160-
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
168+
assertEquals(4, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
161169

162170
pstmt.close();
163171
stmt.close();
@@ -195,6 +203,11 @@ private void timestampTestWTZ() throws SQLException
195203
assertNotNull(t);
196204
assertTrue(t.equals(TS3WTZ));
197205

206+
assertTrue(rs.next());
207+
t = rs.getTimestamp(1);
208+
assertNotNull(t);
209+
assertTrue(t.equals(TS4WTZ));
210+
198211
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
199212

200213
rs.close();
@@ -216,17 +229,22 @@ private void timestampTestWOTZ() throws SQLException
216229
assertTrue(rs.next());
217230
t = rs.getTimestamp(1);
218231
assertNotNull(t);
219-
assertTrue(t.toString().equals(TS1WOTZ_JAVAFORMAT));
232+
assertTrue(t.equals(TS1WOTZ));
220233

221234
assertTrue(rs.next());
222235
t = rs.getTimestamp(1);
223236
assertNotNull(t);
224-
assertTrue(t.toString().equals(TS2WOTZ_JAVAFORMAT));
237+
assertTrue(t.equals(TS2WOTZ));
225238

226239
assertTrue(rs.next());
227240
t = rs.getTimestamp(1);
228241
assertNotNull(t);
229-
assertTrue(t.toString().equals(TS3WOTZ_JAVAFORMAT));
242+
assertTrue(t.equals(TS3WOTZ));
243+
244+
assertTrue(rs.next());
245+
t = rs.getTimestamp(1);
246+
assertNotNull(t);
247+
assertTrue(t.equals(TS4WOTZ));
230248

231249
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
232250

@@ -277,20 +295,21 @@ private static java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int m
277295
private static final java.sql.Timestamp TS3WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, "GMT");
278296
private static final String TS3WTZ_PGFORMAT = "2000-07-07 15:00:00.123+00";
279297

298+
private static final java.sql.Timestamp TS4WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123456000, "GMT");
299+
private static final String TS4WTZ_PGFORMAT = "2000-07-07 15:00:00.123456+00";
300+
280301

281302
private static final java.sql.Timestamp TS1WOTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, null);
282303
private static final String TS1WOTZ_PGFORMAT = "1950-02-07 15:00:00.1";
283-
private static final String TS1WOTZ_JAVAFORMAT = "1950-02-07 15:00:00.1";
284304

285305
private static final java.sql.Timestamp TS2WOTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, null);
286306
private static final String TS2WOTZ_PGFORMAT = "2000-02-07 15:00:00.12";
287-
//there is probably a bug here in that this needs to be .1 instead of .12, but I couldn't find it now
288-
private static final String TS2WOTZ_JAVAFORMAT = "2000-02-07 15:00:00.1";
289307

290308
private static final java.sql.Timestamp TS3WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, null);
291309
private static final String TS3WOTZ_PGFORMAT = "2000-07-07 15:00:00.123";
292-
//there is probably a bug here in that this needs to be .12 instead of .123, but I couldn't find it now
293-
private static final String TS3WOTZ_JAVAFORMAT = "2000-07-07 15:00:00.12";
310+
311+
private static final java.sql.Timestamp TS4WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123456000, null);
312+
private static final String TS4WOTZ_PGFORMAT = "2000-07-07 15:00:00.123456";
294313

295314
private static final String TSWTZ_TABLE = "testtimestampwtz";
296315
private static final String TSWOTZ_TABLE = "testtimestampwotz";

0 commit comments

Comments
 (0)