Skip to content
Permalink
Browse files
fix: #1677 NumberFormatException when fetching PGInterval with small …
…value (#1678)

* fix: #1677 NumberFormatException when fetching PGInterval with small value

* fix: PGInterval.getValue for microsecond values

* ensure getValue always uses at least one decimal place for seconds

* fix: PGInterval.getSeconds for microsecond values
  • Loading branch information
baardsen authored and davecramer committed Jan 28, 2020
1 parent 3dd5dff commit e38868b29cafa7e8a9a5db67adb5a67cc2b5f230
Showing with 63 additions and 31 deletions.
  1. +18 −31 pgjdbc/src/main/java/org/postgresql/util/PGInterval.java
  2. +45 −0 pgjdbc/src/test/java/org/postgresql/test/jdbc2/IntervalTest.java
@@ -7,15 +7,20 @@

import java.io.Serializable;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;

/**
* This implements a class that handles the PostgreSQL interval type.
*/
public class PGInterval extends PGobject implements Serializable, Cloneable {

private static final int MICROS_IN_SECOND = 1000000;

private int years;
private int months;
private int days;
@@ -239,12 +244,16 @@ public void setValue(int years, int months, int days, int hours, int minutes, do
* @return String represented interval
*/
public String getValue() {
return years + " years "
+ months + " mons "
+ days + " days "
+ hours + " hours "
+ minutes + " mins "
+ wholeSeconds + '.' + microSeconds + " secs";
return String.format(
Locale.ROOT,
"%d years %d mons %d days %d hours %d mins %s secs",
years,
months,
days,
hours,
minutes,
new DecimalFormat("0.0#####").format(getSeconds())
);
}

/**
@@ -343,14 +352,7 @@ public void setMinutes(int minutes) {
* @return seconds represented by this interval
*/
public double getSeconds() {
if ( microSeconds < 0) {
if ( wholeSeconds == 0 ) {
return Double.parseDouble("-0." + -microSeconds);
} else {
return Double.parseDouble("" + wholeSeconds + '.' + -microSeconds);
}
}
return Double.parseDouble("" + wholeSeconds + '.' + microSeconds );
return wholeSeconds + (double) microSeconds / MICROS_IN_SECOND;
}

public int getWholeSeconds() {
@@ -367,23 +369,8 @@ public int getMicroSeconds() {
* @param seconds seconds to set
*/
public void setSeconds(double seconds) {
String str = Double.toString(seconds);
int decimal = str.indexOf('.');
if (decimal > 0) {

/* how many 10's do we need to multiply by to get microseconds */
String micSeconds = str.substring(decimal + 1);
int power = 6 - micSeconds.length();

microSeconds = Integer.parseInt(micSeconds) * (int)Math.pow(10,power);
wholeSeconds = Integer.parseInt(str.substring(0,decimal));
} else {
microSeconds = 0;
wholeSeconds = Integer.parseInt(str);
}
if ( seconds < 0 ) {
microSeconds = -microSeconds;
}
wholeSeconds = (int) seconds;
microSeconds = (int) Math.round((seconds - wholeSeconds) * MICROS_IN_SECOND);
}

/**
@@ -305,6 +305,51 @@ public void testISO8601() throws Exception {
assertEquals(-4, pgi.getHours());
}

@Test
public void testSmallValue() throws SQLException {
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO testinterval VALUES (?)");
pstmt.setObject(1, new PGInterval("0.0001 seconds"));
pstmt.executeUpdate();
pstmt.close();

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT v FROM testinterval");
assertTrue(rs.next());
PGInterval pgi = (PGInterval) rs.getObject(1);
assertEquals(0, pgi.getYears());
assertEquals(0, pgi.getMonths());
assertEquals(0, pgi.getDays());
assertEquals(0, pgi.getHours());
assertEquals(0, pgi.getMinutes());
assertEquals(0, pgi.getWholeSeconds());
assertEquals(100, pgi.getMicroSeconds());
assertFalse(rs.next());
rs.close();
stmt.close();
}

@Test
public void testGetValueForSmallValue() throws SQLException {
PGInterval orig = new PGInterval("0.0001 seconds");
PGInterval copy = new PGInterval(orig.getValue());

assertEquals(orig, copy);
}

@Test
public void testGetSecondsForSmallValue() throws SQLException {
PGInterval pgi = new PGInterval("0.000001 seconds");

assertEquals(0.000001, pgi.getSeconds(), 0.000000001);
}

@Test
public void testMicroSecondsAreRoundedToNearest() throws SQLException {
PGInterval pgi = new PGInterval("0.0000007 seconds");

assertEquals(1, pgi.getMicroSeconds());
}

private java.sql.Date makeDate(int y, int m, int d) {
return new java.sql.Date(y - 1900, m - 1, d);
}

0 comments on commit e38868b

Please sign in to comment.