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

spring-data-jdbc and postgres: Trailing junk on timestamp #935

Closed
ghost opened this issue Mar 9, 2021 · 9 comments
Closed

spring-data-jdbc and postgres: Trailing junk on timestamp #935

ghost opened this issue Mar 9, 2021 · 9 comments
Assignees
Labels
type: bug A general bug

Comments

@ghost
Copy link

ghost commented Mar 9, 2021

Original question here: https://stackoverflow.com/q/66484578

Small gradle project with a junit test to reproduce the error: https://github.com/schachtelhalm/minimal-demo

With spring boot 2.3.8 this junit test doesn't fail, with 2.3.9 it fails with
java.lang.NumberFormatException: Trailing junk on timestamp: 'T21:26:13.318881+01:00'
Tested with openjdk 11.0.10.
Complete stacktrace on minimal-demo page.

The query method is in a Repository that extends CrudRepository:

    @Query("SELECT` * FROM animal WHERE updated_at > :lastUpdate")
    List<Animal> findByUpdatedAtGreaterThan(@Param("lastUpdate") OffsetDateTime lastUpdate);

The entity has a field private Timestamp updatedAt;

When I tried to debug the original application I set a breakpoint in org.postgresql.jdbc.TimestampUtils.parseBackendTimestamp(). With spring boot 2.3.8 I think I only hit the method for timestamps from the database rows, but not for the parameter of the query. With 2.3.9 the method parseBackendTimestamp() was also called for the parameter I'd used with curl requests for the RestController.

@ghost
Copy link
Author

ghost commented Mar 9, 2021

i have no idea what the problem is, if it is postgresql or spring-data related, or if there is something wrong in our application. And if so, why did it work until I upgraded spring boot? Any hints would be much appreciated.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 9, 2021
@schauder
Copy link
Contributor

I haven't found the exact reason yet of what is going wrong.
But everything does work if you use Instant instead of OffsetDateTime.

I'm always very sceptical when I see time and date like datatypes with timezone information used in persistent storage, since it seems to mingle two very different concepts: a point in time and a rough approximation of a location/cultural context.

Most of the time Instant is the correct type to use and timezone information if needed at all should come from a different source: The user observing the Instant, or the entity to which the Instant relates.

@schauder schauder reopened this Mar 10, 2021
@schauder schauder self-assigned this Mar 10, 2021
@jerrychen-afterpay
Copy link

jerrychen-afterpay commented Mar 11, 2021

Also ran into this issue today, but with SpringBoot 2.4.3. We also are running postgresql. The issue occurs when we run updates on a table of the form (other fields omitted):

@Table("table_name")
data class MyTable(
    @Id @Column("id") val id: UUID,
    @Column("created_at") val createdAt: OffsetDateTime = OffsetDateTime.now(),
    @Column("updated_at") val updatedAt: OffsetDateTime = OffsetDateTime.now()
)

The code works for a different table that doesn't have an updated_at field, i.e. it looks like the following (other fields omitted):

@Table("table_2_name")
data class MyOtherTable(
    @Id @Column("id") val id: UUID,
    @Column("updated_at") val createdAt: OffsetDateTime = OffsetDateTime.now()
)

@ghost
Copy link
Author

ghost commented Mar 14, 2021

@schauder The application (that I kind of inherited) uses UTC for all dates (and for timestamp with time zone, the internally stored value in Postgres is always in UTC). So we don't really store a time zone.
According to the Postgresql Driver docs, the Java type for TIMESTAMP WITH TIMEZONE is OffsetDateTime and they also mention: "Note that ZonedDateTime, Instant and [...] are not supported".
Is this relevant at all when using spring-data-jdbc?

@rattermeyer
Copy link

Also ran into the problem today. But I would have blamed the PostgreSQL driver for not corectly parsing the OffeseDateTime string representation. It does not expect the seperating 'T'. However PostgreSQL documentation suggests, it should work.
Haven't tried without spring-data-jdbc.

@schauder
Copy link
Contributor

The problem seems to be that we are now setting the sqlType in the SqlParameterSource and use the wrong java.sql.Types value: 93 (TIMESTAMP) instead of 2014 (TIMESTAMP_WITH_TIMEZONE).

@schauder schauder added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 13, 2021
schauder added a commit that referenced this issue May 19, 2021
schauder added a commit that referenced this issue May 19, 2021
Dialects may now register a list of converters to take into consideration when reading or writing properties.

See `JdbcSqlServerDialect` for an example.

By default `OffsetDateTime` does not get converted anymore.
If a database needs a conversion it can register it by implementing `Dialect.getConverters()` as described above.

Closes #935
@schauder
Copy link
Contributor

I just created a PR that hopefully fixes the issue. If anybody can give that a try, that would be helpful.

Note, that in it's current form it breaks code that inherits from AbstractJdbcConfiguration and overwrites customConversions(). That method got replaced by one with a Dialect argument.

schauder added a commit that referenced this issue May 21, 2021
Originial pull request #981
See #935
schauder added a commit that referenced this issue May 31, 2021
Removes superfluous method.
Applied feedback from review: Formatting, Naming, and improved backward compatibility.

Originial pull request #981
See #935
schauder pushed a commit that referenced this issue May 31, 2021
Dialects now can define a set of known simple types the driver can handle without further interaction. This is done to avoid warnings during converter registration for types known in one environment but not the other.
Also move types around a bit, change visibility and make sure jdbc specific dialects inherit converters from their parents.

Original pull request #981
See #935
@Kshitij09
Copy link

I'm still getting "Trailing Junk on timestamp: 'T07:02:27.894774Z'". I've even aligned OffsetDateTime to UTC using following snippet

var odtNow = OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC);

Are we supposed to use Instant? Postgres Documentation says OffsetDateTime is supported in JDBC 4.2

@schauder
Copy link
Contributor

The problem is only in so far the JDBC driver that the JDBC driver of most databases just drops the timezone.

Do you use one of the 2.3 milestone releases of Spring Data JDBC?
If so an you still see this problem we'd need a new issue and a reproducer.

nilsjorgen added a commit to navikt/sykepengesoknad-narmesteleder-varsler that referenced this issue Dec 10, 2021
- Oppdatert KafkaErrorHandler til å arve DefaultErrorHandler
- Oppdatert Kafka config.
- Endre til bruk av Instant i stedet for OffsetDateTime på grunn av mulig bug i Spring:
  spring-projects/spring-data-relational#935
  Skulle vært fikset i spring-data-jdbc-2.3.0, men ser ut som det ble igjeninnført med
  spring-boot-2.6.1.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
5 participants