Skip to content

Commit

Permalink
feat: implement JSR-310 support in setObject
Browse files Browse the repository at this point in the history
JSR-310 support is currently missing in both setObject methods in
PgPreparedStatement.

Implement JSR-310 support in PreparedStatement.setObject

Closes #476
  • Loading branch information
marschall authored and vlsi committed Jan 7, 2016
1 parent a65b4b9 commit e52f7e3
Show file tree
Hide file tree
Showing 5 changed files with 524 additions and 12 deletions.
Expand Up @@ -55,6 +55,12 @@
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.sql.Types; import java.sql.Types;
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
//#endif
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
Expand Down Expand Up @@ -617,6 +623,11 @@ public void setObject(int parameterIndex, Object in, int targetSqlType, int scal
java.sql.Date tmpd; java.sql.Date tmpd;
if (in instanceof java.util.Date) { if (in instanceof java.util.Date) {
tmpd = new java.sql.Date(((java.util.Date) in).getTime()); tmpd = new java.sql.Date(((java.util.Date) in).getTime());
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
} else if (in instanceof LocalDate) {
setDate(parameterIndex, (LocalDate) in);
break;
//#endif
} else { } else {
tmpd = connection.getTimestampUtils().toDate(null, in.toString()); tmpd = connection.getTimestampUtils().toDate(null, in.toString());
} }
Expand All @@ -630,25 +641,51 @@ public void setObject(int parameterIndex, Object in, int targetSqlType, int scal
java.sql.Time tmpt; java.sql.Time tmpt;
if (in instanceof java.util.Date) { if (in instanceof java.util.Date) {
tmpt = new java.sql.Time(((java.util.Date) in).getTime()); tmpt = new java.sql.Time(((java.util.Date) in).getTime());
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
} else if (in instanceof LocalTime) {
setTime(parameterIndex, (LocalTime) in);
break;
//#endif
} else { } else {
tmpt = connection.getTimestampUtils().toTime(null, in.toString()); tmpt = connection.getTimestampUtils().toTime(null, in.toString());
} }
setTime(parameterIndex, tmpt); setTime(parameterIndex, tmpt);
} }
break; break;
case Types.TIMESTAMP: case Types.TIMESTAMP:
if (in instanceof java.sql.Timestamp) { if (in instanceof PGTimestamp) {
setObject(parameterIndex, in);
} else if (in instanceof java.sql.Timestamp) {
setTimestamp(parameterIndex, (java.sql.Timestamp) in); setTimestamp(parameterIndex, (java.sql.Timestamp) in);
} else { } else {
java.sql.Timestamp tmpts; java.sql.Timestamp tmpts;
if (in instanceof java.util.Date) { if (in instanceof java.util.Date) {
tmpts = new java.sql.Timestamp(((java.util.Date) in).getTime()); tmpts = new java.sql.Timestamp(((java.util.Date) in).getTime());
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
} else if (in instanceof LocalDateTime) {
setTimestamp(parameterIndex, (LocalDateTime) in);
break;
//#endif
} else { } else {
tmpts = connection.getTimestampUtils().toTimestamp(null, in.toString()); tmpts = connection.getTimestampUtils().toTimestamp(null, in.toString());
} }
setTimestamp(parameterIndex, tmpts); setTimestamp(parameterIndex, tmpts);
} }
break; break;
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
case Types.TIMESTAMP_WITH_TIMEZONE:
if (in instanceof OffsetDateTime) {
setTimestamp(parameterIndex, (OffsetDateTime) in);
} else if (in instanceof PGTimestamp) {
setObject(parameterIndex, in);
} else {
throw new PSQLException(
GT.tr("Cannot cast an instance of {0} to type {1}",
new Object[]{in.getClass().getName(), "Types.TIMESTAMP_WITH_TIMEZONE"}),
PSQLState.INVALID_PARAMETER_TYPE);
}
break;
//#endif
case Types.BIT: case Types.BIT:
setBoolean(parameterIndex, castToBoolean(in)); setBoolean(parameterIndex, castToBoolean(in));
break; break;
Expand Down Expand Up @@ -985,6 +1022,16 @@ public void setObject(int parameterIndex, Object x) throws SQLException {
setPGobject(parameterIndex, (PGobject) x); setPGobject(parameterIndex, (PGobject) x);
} else if (x instanceof Character) { } else if (x instanceof Character) {
setString(parameterIndex, ((Character) x).toString()); setString(parameterIndex, ((Character) x).toString());
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
} else if (x instanceof LocalDate) {
setDate(parameterIndex, (LocalDate) x);
} else if (x instanceof LocalTime) {
setTime(parameterIndex, (LocalTime) x);
} else if (x instanceof LocalDateTime) {
setTimestamp(parameterIndex, (LocalDateTime) x);
} else if (x instanceof OffsetDateTime) {
setTimestamp(parameterIndex, (OffsetDateTime) x);
//#endif
} else if (x instanceof Map) { } else if (x instanceof Map) {
setMap(parameterIndex, (Map) x); setMap(parameterIndex, (Map) x);
} else { } else {
Expand Down Expand Up @@ -1422,6 +1469,28 @@ public void setTimestamp(int i, Timestamp t, java.util.Calendar cal) throws SQLE
bindString(i, connection.getTimestampUtils().toString(cal, t), oid); bindString(i, connection.getTimestampUtils().toString(cal, t), oid);
} }


//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
private void setDate(int i, LocalDate localDate) throws SQLException {
int oid = Oid.DATE;
bindString(i, connection.getTimestampUtils().toString(localDate), oid);
}

private void setTime(int i, LocalTime localTime) throws SQLException {
int oid = Oid.TIME;
bindString(i, connection.getTimestampUtils().toString(localTime), oid);
}

private void setTimestamp(int i, LocalDateTime localDateTime) throws SQLException {
int oid = Oid.TIMESTAMP;
bindString(i, connection.getTimestampUtils().toString(localDateTime), oid);
}

private void setTimestamp(int i, OffsetDateTime offsetDateTime) throws SQLException {
int oid = Oid.TIMESTAMPTZ;
bindString(i, connection.getTimestampUtils().toString(offsetDateTime), oid);
}
//#endif

public ParameterMetaData createParameterMetaData(BaseConnection conn, int oids[]) public ParameterMetaData createParameterMetaData(BaseConnection conn, int oids[])
throws SQLException { throws SQLException {
return new PgParameterMetaData(conn, oids); return new PgParameterMetaData(conn, oids);
Expand Down
136 changes: 127 additions & 9 deletions pgjdbc/src/main/java/org/postgresql/jdbc/TimestampUtils.java
Expand Up @@ -19,6 +19,15 @@
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.chrono.IsoEra;
import java.time.temporal.ChronoField;
//#endif
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;
Expand Down Expand Up @@ -398,9 +407,9 @@ public synchronized String toString(Calendar cal, Timestamp x) {


public synchronized String toString(Calendar cal, Date x) { public synchronized String toString(Calendar cal, Date x) {
if (x.getTime() == PGStatement.DATE_POSITIVE_INFINITY) { if (x.getTime() == PGStatement.DATE_POSITIVE_INFINITY) {
sbuf.append("infinity"); return "infinity";
} else if (x.getTime() == PGStatement.DATE_NEGATIVE_INFINITY) { } else if (x.getTime() == PGStatement.DATE_NEGATIVE_INFINITY) {
sbuf.append("-infinity"); return "-infinity";
} }


cal = setupCalendar(cal); cal = setupCalendar(cal);
Expand Down Expand Up @@ -433,34 +442,42 @@ public synchronized String toString(Calendar cal, Time x) {


private static void appendDate(StringBuilder sb, Calendar cal) { private static void appendDate(StringBuilder sb, Calendar cal) {
int l_year = cal.get(Calendar.YEAR); int l_year = cal.get(Calendar.YEAR);
int l_month = cal.get(Calendar.MONTH) + 1;
int l_day = cal.get(Calendar.DAY_OF_MONTH);
appendDate(sb, l_year, l_month, l_day);
}

private static void appendDate(StringBuilder sb, int year, int month, int day) {
// always use at least four digits for the year so very // always use at least four digits for the year so very
// early years, like 2, don't get misinterpreted // early years, like 2, don't get misinterpreted
// //
int prevLength = sb.length(); int prevLength = sb.length();
sb.append(l_year); sb.append(year);
int leadingZerosForYear = 4 - (sb.length() - prevLength); int leadingZerosForYear = 4 - (sb.length() - prevLength);
if (leadingZerosForYear > 0) { if (leadingZerosForYear > 0) {
sb.insert(prevLength, ZEROS, 0, leadingZerosForYear); sb.insert(prevLength, ZEROS, 0, leadingZerosForYear);
} }


sb.append('-'); sb.append('-');
int l_month = cal.get(Calendar.MONTH) + 1; sb.append(NUMBERS[month]);
sb.append(NUMBERS[l_month]);
sb.append('-'); sb.append('-');
int l_day = cal.get(Calendar.DAY_OF_MONTH); sb.append(NUMBERS[day]);
sb.append(NUMBERS[l_day]);
} }


private static void appendTime(StringBuilder sb, Calendar cal, int nanos) { private static void appendTime(StringBuilder sb, Calendar cal, int nanos) {
int hours = cal.get(Calendar.HOUR_OF_DAY); int hours = cal.get(Calendar.HOUR_OF_DAY);
int minutes = cal.get(Calendar.MINUTE);
int seconds = cal.get(Calendar.SECOND);
appendTime(sb, hours, minutes, seconds, nanos);
}

private static void appendTime(StringBuilder sb, int hours, int minutes, int seconds, int nanos) {
sb.append(NUMBERS[hours]); sb.append(NUMBERS[hours]);


sb.append(':'); sb.append(':');
int minutes = cal.get(Calendar.MINUTE);
sb.append(NUMBERS[minutes]); sb.append(NUMBERS[minutes]);


sb.append(':'); sb.append(':');
int seconds = cal.get(Calendar.SECOND);
sb.append(NUMBERS[seconds]); sb.append(NUMBERS[seconds]);


// Add nanoseconds. // Add nanoseconds.
Expand All @@ -480,6 +497,10 @@ private static void appendTime(StringBuilder sb, Calendar cal, int nanos) {
private void appendTimeZone(StringBuilder sb, java.util.Calendar cal) { private void appendTimeZone(StringBuilder sb, java.util.Calendar cal) {
int offset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 1000; int offset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 1000;


appendTimeZone(sb, offset);
}

private void appendTimeZone(StringBuilder sb, int offset) {
int absoff = Math.abs(offset); int absoff = Math.abs(offset);
int hours = absoff / 60 / 60; int hours = absoff / 60 / 60;
int mins = (absoff - hours * 60 * 60) / 60; int mins = (absoff - hours * 60 * 60) / 60;
Expand All @@ -505,6 +526,103 @@ private static void appendEra(StringBuilder sb, Calendar cal) {
} }
} }


//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
public synchronized String toString(LocalDate localDate) {
if (LocalDate.MAX.equals(localDate)) {
return "infinity";
} else if (LocalDate.MIN.equals(localDate)) {
return "-infinity";
}

sbuf.setLength(0);

appendDate(sbuf, localDate);
appendEra(sbuf, localDate);

return sbuf.toString();
}

public synchronized String toString(LocalTime localTime) {
if (LocalTime.MAX.equals(localTime)) {
return "infinity";
} else if (LocalTime.MIN.equals(localTime)) {
return "-infinity";
}

sbuf.setLength(0);

appendTime(sbuf, localTime);

return sbuf.toString();
}


public synchronized String toString(OffsetDateTime offsetDateTime) {
if (OffsetDateTime.MAX.equals(offsetDateTime)) {
return "infinity";
} else if (OffsetDateTime.MIN.equals(offsetDateTime)) {
return "-infinity";
}

sbuf.setLength(0);

LocalDateTime localDateTime = offsetDateTime.toLocalDateTime();
LocalDate localDate = localDateTime.toLocalDate();
appendDate(sbuf, localDate);
sbuf.append(' ');
appendTime(sbuf, localDateTime.toLocalTime());
appendTimeZone(sbuf, offsetDateTime.getOffset());
appendEra(sbuf, localDate);

return sbuf.toString();
}

public synchronized String toString(LocalDateTime localDateTime) {
if (LocalDateTime.MAX.equals(localDateTime)) {
return "infinity";
} else if (LocalDateTime.MIN.equals(localDateTime)) {
return "-infinity";
}

sbuf.setLength(0);

LocalDate localDate = localDateTime.toLocalDate();
appendDate(sbuf, localDate);
sbuf.append(' ');
appendTime(sbuf, localDateTime.toLocalTime());
appendEra(sbuf, localDate);

return sbuf.toString();
}

private static void appendDate(StringBuilder sb, LocalDate localDate) {
int year = Math.abs(localDate.getYear()); // year is negative for BC dates
int month = localDate.getMonthValue();
int day = localDate.getDayOfMonth();
appendDate(sb, year, month, day);
}

private static void appendTime(StringBuilder sb, LocalTime localTime) {
int hours = localTime.getHour();
int minutes = localTime.getMinute();
int seconds = localTime.getSecond();
int nanos = localTime.getNano();
appendTime(sb, hours, minutes, seconds, nanos);
}

private void appendTimeZone(StringBuilder sb, ZoneOffset offset) {
int offsetSeconds = offset.getTotalSeconds();

appendTimeZone(sb, offsetSeconds);
}

private static void appendEra(StringBuilder sb, LocalDate localDate) {
if (localDate.get(ChronoField.ERA) == IsoEra.BCE.getValue()) {
sb.append(" BC");
}
}
//#endif

private static int skipWhitespace(char[] s, int start) { private static int skipWhitespace(char[] s, int start) {
int slen = s.length; int slen = s.length;
for (int i = start; i < slen; i++) { for (int i = start; i < slen; i++) {
Expand Down
Expand Up @@ -600,8 +600,10 @@ public void testGetXml() throws SQLException {


/** /**
* Test the behavior getObject for money columns. * Test the behavior getObject for money columns.
*
* The test is ignored as it is locale-dependent.
*/ */
public void testGetMoney() throws SQLException { public void _testGetMoney() throws SQLException {
Statement stmt = _conn.createStatement(); Statement stmt = _conn.createStatement();
String expected = "12.34"; String expected = "12.34";
stmt.executeUpdate(TestUtil.insertSQL("table1","money_column","'12.34'::float8::numeric::money")); stmt.executeUpdate(TestUtil.insertSQL("table1","money_column","'12.34'::float8::numeric::money"));
Expand Down
Expand Up @@ -13,7 +13,7 @@
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({SimpleJdbc42Test.class, CustomizeDefaultFetchSizeTest.class, GetObject310Test.class}) @SuiteClasses({SimpleJdbc42Test.class, CustomizeDefaultFetchSizeTest.class, GetObject310Test.class, SetObject310Test.class})
public class Jdbc42TestSuite { public class Jdbc42TestSuite {


} }

0 comments on commit e52f7e3

Please sign in to comment.