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

setTimestamp use timestamptz db type #3220

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ dependency-reduced-pom.xml
buildNumber.properties

# Ignore folders used to build binaries for old Java
bin
/eclipsebin/

9 changes: 9 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/PGProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,15 @@ public enum PGProperty {
"0",
"The timeout value in seconds max(2147484) used for socket read operations."),

/**
* If true it uses time stamp with time zone type always for java sql Timestamp
* The default is {@code false} for compatibility.
*/
SQL_TIMESTAMPTZ_ALWAYS(
"sqlTimestamptzAlways",
"false",
"If true it uses time stamp with time zone type for java Timestamp. The default is (@code false)"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/time stamp/timestamp


/**
* Control use of SSL: empty or {@code true} values imply {@code sslmode==verify-full}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1849,4 +1849,12 @@ public void setCleanupSavePoints(final boolean cleanupSavepoints) {
public boolean isReWriteBatchedInserts() {
return getReWriteBatchedInserts();
}

public boolean isSqlTimestamptzAlways() {
return PGProperty.SQL_TIMESTAMPTZ_ALWAYS.getBoolean(properties);
}

public void setSqlTimestamptzAlways(boolean sqlTimestamptzAlways) {
PGProperty.SQL_TIMESTAMPTZ_ALWAYS.set(properties, sqlTimestamptzAlways);
}
}
8 changes: 8 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ private enum ReadOnlyBehavior {
private final boolean logServerErrorDetail;
// Bind String to UNSPECIFIED or VARCHAR?
private final boolean bindStringAsVarchar;
// Uses timestamptz always for java sql Timestamp
private final boolean sqlTimestamptzAlways;

// Current warnings; there might be more on queryExecutor too.
private @Nullable SQLWarning firstWarning;
Expand Down Expand Up @@ -287,6 +289,8 @@ public PgConnection(HostSpec[] hostSpecs,

this.hideUnprivilegedObjects = PGProperty.HIDE_UNPRIVILEGED_OBJECTS.getBoolean(info);

this.sqlTimestamptzAlways = PGProperty.SQL_TIMESTAMPTZ_ALWAYS.getBoolean(info);

// get oids that support binary transfer
Set<Integer> binaryOids = getBinaryEnabledOids(info);
// get oids that should be disabled from transfer
Expand Down Expand Up @@ -1964,4 +1968,8 @@ public PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException {
this.xmlFactoryFactory = xmlFactoryFactory;
return xmlFactoryFactory;
}

public boolean isSqlTimestamptzAlways() {
return sqlTimestamptzAlways;
}
}
18 changes: 18 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map;
Expand Down Expand Up @@ -682,6 +684,10 @@ public void setObject(@Positive int parameterIndex, @Nullable Object in,
} else if (in instanceof LocalDateTime) {
setTimestamp(parameterIndex, (LocalDateTime) in);
break;
} else if (in instanceof Instant) {
tmpts = Timestamp.from( (Instant) in );
} else if (in instanceof ZonedDateTime) {
tmpts = Timestamp.valueOf( ((ZonedDateTime) in).toLocalDateTime());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm ZonedDateTime.toLocalDateTime() would just forget the timezone of the zdt?
Also, why would it support ZonedDateTime, but not OffsetDateTime?

I might be wrong with my assumptions here of course.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your assumption is correct, so I changed it to use OffsetDateTime type so that time zone information is not lost but stored into the timestamptz.

Anyway, if you use OffsetDateTime to fetch data back form the db, the time zone info is lost as illustrated by the test case TimestamptzTest.test_ZonedDateTime_StoreAndSelect().
How is the correct way to get back the information of the timezone (without using string) ?

NOTE: in our application we always store dates in UTC time zone in the db to avoid any problem. If we need to store information about the time zone to use for some business logic that is stored into a separate fields independent to any stored timestamptz.

} else {
tmpts = getTimestampUtils().toTimestamp(getDefaultCalendar(), in.toString().getBytes());
}
Expand All @@ -693,6 +699,10 @@ public void setObject(@Positive int parameterIndex, @Nullable Object in,
setTimestamp(parameterIndex, (OffsetDateTime) in);
} else if (in instanceof PGTimestamp) {
setObject(parameterIndex, in);
} else if (in instanceof Instant) {
setTimestamp(parameterIndex, Timestamp.from( (Instant) in ));
} else if (in instanceof ZonedDateTime) {
setTimestamp(parameterIndex, Timestamp.valueOf(((ZonedDateTime) in).toLocalDateTime()));
} else {
throw new PSQLException(
GT.tr("Cannot cast an instance of {0} to type {1}",
Expand Down Expand Up @@ -1035,6 +1045,10 @@ public void setObject(@Positive int parameterIndex, @Nullable Object x) throws S
setTime(parameterIndex, (Time) x);
} else if (x instanceof Timestamp) {
setTimestamp(parameterIndex, (Timestamp) x);
} else if (x instanceof Instant ) {
setTimestamp(parameterIndex, Timestamp.from((Instant) x ));
} else if (x instanceof ZonedDateTime ) {
setTimestamp(parameterIndex, ((ZonedDateTime) x).toOffsetDateTime());
} else if (x instanceof Boolean) {
setBoolean(parameterIndex, (Boolean) x);
} else if (x instanceof Byte) {
Expand Down Expand Up @@ -1506,6 +1520,10 @@ public void setTimestamp(@Positive int i, @Nullable Timestamp t,
if (cal == null) {
cal = getDefaultCalendar();
}

if (connection.isSqlTimestamptzAlways()) {
oid = Oid.TIMESTAMPTZ;
}
bindString(i, getTimestampUtils().toString(cal, t), oid);
}

Expand Down
12 changes: 12 additions & 0 deletions pgjdbc/src/test/java/org/postgresql/test/jdbc2/BaseTest4.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,16 @@ public enum StringType {
UNSPECIFIED, VARCHAR
}

public enum TimestamptzAlways {
YES, NO
}

protected Connection con;
protected BinaryMode binaryMode;
private ReWriteBatchedInserts reWriteBatchedInserts;
protected PreferQueryMode preferQueryMode;
private StringType stringType;
private TimestamptzAlways timestamptzAlways;

protected void updateProperties(Properties props) {
if (binaryMode == BinaryMode.FORCE) {
Expand All @@ -59,6 +64,9 @@ protected void updateProperties(Properties props) {
if (stringType != null) {
PGProperty.STRING_TYPE.set(props, stringType.name().toLowerCase(Locale.ROOT));
}
if (timestamptzAlways == TimestamptzAlways.YES) {
PGProperty.SQL_TIMESTAMPTZ_ALWAYS.set(props, true);
}
}

protected void forceBinary(Properties props) {
Expand All @@ -83,6 +91,10 @@ public void setReWriteBatchedInserts(
this.reWriteBatchedInserts = reWriteBatchedInserts;
}

public void setTimestamptzAlways(TimestamptzAlways timestamptzAlways) {
this.timestamptzAlways = timestamptzAlways;
}

@Before
public void setUp() throws Exception {
Properties props = new Properties();
Expand Down