Re: JDBC setTimestamp question - Mailing list pgsql-jdbc

From arons
Subject Re: JDBC setTimestamp question
Date
Msg-id CA+XOKQC67VVYk6HfPbFxWYDuwR4BmVzhWhBC=La1y3jmYNta2Q@mail.gmail.com
Whole thread Raw
In response to Re: JDBC setTimestamp question  (Dave Cramer <davecramer@postgres.rocks>)
Responses Re: JDBC setTimestamp question
List pgsql-jdbc
Well java Timestamp reflect the java Date which is intended to reflect coordinated universal time (UTC) in most cases.
That is not the same in postgres with timestamp.

So in generally timestamptz is what you need.

JDBC api should in my opinion reflect that nature, so a call to setTimestamp should reflect the that nature too.

Also in the last line bindString(i, getTimestampUtils().toString(cal, t), oid) it calls:

public synchronized String toString(@Nullable Calendar cal, Timestamp x) {

return toString(cal, x, true);

}

public synchronized String toString(@Nullable Calendar cal, Timestamp x, boolean withTimeZone) {


Where the timezone is correctly always passed.


In the current implementation if I do not force the conversion to timestamptz immediately we lost the timezone...not really transparent to the java user.
" PostgreSQL never examines the content of a literal string before determining its type, and therefore will treat both of the above as timestamp without time zone. To ensure that a literal is treated as timestamp with time zone, give it the correct explicit type: ... "
That is the most scary to me, so without an explicit cast I can maybe lost the timezone information even if I pass on java side.
Again an explicit cast timestamptz -> timestamp would do much more sense to me instead of avoid it, that would be clear to the user.

In addition, the currently implementation force to write specific code or specific query based on the the back-end DB.
In our software we are supporting different DB natures and I would expect the same behavior on different DBs for the same simple java code and query, which is not the case here.

Maybe the code can be reconsider.

Thanks
Renzo

On Wed, Jan 25, 2023 at 4:19 PM Dave Cramer <davecramer@postgres.rocks> wrote:



On Wed, 25 Jan 2023 at 10:15, arons <arons7@gmail.com> wrote:
I checked the source code and inside the method org.postgresql.jdbc.PgPreparedStatement.setTimestamp(int, Timestamp, Calendar) I found the code I was interesting to:

int oid = Oid.UNSPECIFIED;

// Use UNSPECIFIED as a compromise to get both TIMESTAMP and TIMESTAMPTZ working.

// This is because you get this in a +1300 timezone:

//

// template1=# select '2005-01-01 15:00:00 +1000'::timestamptz;

// timestamptz

// ------------------------

// 2005-01-01 18:00:00+13

// (1 row)

// template1=# select '2005-01-01 15:00:00 +1000'::timestamp;

// timestamp

// ---------------------

// 2005-01-01 15:00:00

// (1 row)

// template1=# select '2005-01-01 15:00:00 +1000'::timestamptz::timestamp;

// timestamp

// ---------------------

// 2005-01-01 18:00:00

// (1 row)

// So we want to avoid doing a timestamptz -> timestamp conversion, as that

// will first convert the timestamptz to an equivalent time in the server's

// timezone (+1300, above), then turn it into a timestamp with the "wrong"

// time compared to the string we originally provided. But going straight

// to timestamp is OK as the input parser for timestamp just throws away

// the timezone part entirely. Since we don't know ahead of time what type

// we're actually dealing with, UNSPECIFIED seems the lesser evil, even if it

// does give more scope for type-mismatch errors being silently hidden.

// If a PGTimestamp is used, we can define the OID explicitly.

if (t instanceof PGTimestamp) {

PGTimestamp pgTimestamp = (PGTimestamp) t;

if (pgTimestamp.getCalendar() == null) {

oid = Oid.TIMESTAMP;

} else {

oid = Oid.TIMESTAMPTZ;

cal = pgTimestamp.getCalendar();

}

}

if (cal == null) {

cal = getDefaultCalendar();

}

bindString(i, getTimestampUtils().toString(cal, t), oid);




I saw that I can use PGTimestamp instead of sql Timestamp.

In that case all works fine.

Anyway I do not fully understand the comment and why we set oid = Oid.UNSPECIFIED; in case of normal sql Timestamp.

Is there any different between a java.sql.Timestamp.Timestamp and org.postgresql.util.PGTimestamp.PGTimestamp ?

Cannot be use oid = Oid.TIMESTAMP in any other case as when t is not an instance of PGTimestamp?


Thanks

Renzo




We use unspecified because we don't know whether setTimestamp is setting a timestamptz or a timestamp. 

Dave

pgsql-jdbc by date:

Previous
From: Dave Cramer
Date:
Subject: Re: JDBC setTimestamp question
Next
From: Dave Cramer
Date:
Subject: Re: JDBC setTimestamp question