Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 18 additions & 31 deletions pgjdbc/src/main/java/org/postgresql/util/PGInterval.java
Expand Up @@ -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;
Expand Down Expand Up @@ -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())
);
}

/**
Expand Down Expand Up @@ -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() {
Expand All @@ -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);
}

/**
Expand Down
45 changes: 45 additions & 0 deletions pgjdbc/src/test/java/org/postgresql/test/jdbc2/IntervalTest.java
Expand Up @@ -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());
}

davecramer marked this conversation as resolved.
Show resolved Hide resolved
private java.sql.Date makeDate(int y, int m, int d) {
return new java.sql.Date(y - 1900, m - 1, d);
}
Expand Down