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 JDBC does not recognize LocalDate and LocalDateTime in javaType to sqlType Mapping #28778

Closed
DhavalShewale opened this issue Jul 8, 2022 · 3 comments
Assignees
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Milestone

Comments

@DhavalShewale
Copy link

In class, StatementCreatorUtils, spring jdbc does not recognize LocalDate and LocalDateTime in javaTypeToSqlTypeMap and as a result they get categorized as UNKOWN_TYPE.

LocalDate and LocalDateTime have been available for years and we should try to include them in the framework.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 8, 2022
@jhoeller jhoeller self-assigned this Jul 8, 2022
@jhoeller jhoeller added in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jul 8, 2022
@jhoeller jhoeller added this to the 5.3.22 milestone Jul 8, 2022
@jhoeller
Copy link
Contributor

jhoeller commented Jul 8, 2022

Good catch, those should have a standard SQL type mapping (even if this mapping mechanism is only really used in our BeanPropertySqlParameterSource). I've added the following, to be committed along with a few other 5.3.x backports:

		javaTypeToSqlTypeMap.put(LocalDate.class, Types.DATE);
		javaTypeToSqlTypeMap.put(LocalTime.class, Types.TIME);
		javaTypeToSqlTypeMap.put(LocalDateTime.class, Types.TIMESTAMP);

simonbasle added a commit to simonbasle/spring-framework that referenced this issue Mar 15, 2023
This commit adds mapping for two types from the `java.time` package,
complementing the types that are already translatable to Sql types
TIME, DATE and TIMESTAMP:
 - `OffsetTime` maps to a `TIME_WITH_TIMEZONE`
 - `OffsetDateTime` maps to a `TIMESTAMP_WITH_TIMEZONE`

This is in accordance with the B.4 table provided in the JDBC 4.2
specification.

When preparing statements, these `java.time` types use the `setObject`
method. Tests covering the 5 `java.time` classes have also been added.

See spring-projectsgh-28778
See spring-projectsgh-28527
simonbasle added a commit that referenced this issue Apr 4, 2023
This commit adds mapping for two types from the `java.time` package,
complementing the types that are already translatable to Sql types
TIME, DATE and TIMESTAMP:
 - `OffsetTime` maps to a `TIME_WITH_TIMEZONE`
 - `OffsetDateTime` maps to a `TIMESTAMP_WITH_TIMEZONE`

This is in accordance with the B.4 table provided in the JDBC 4.2
specification.

When preparing statements, these `java.time` types use the `setObject`
method. Tests covering the 5 `java.time` classes have also been added.

See gh-28778
See gh-28527
Closes gh-30123
@slatake-swi
Copy link

First of all I would like to thank the spring framework team for doing there great work & making us available newer version and maintaining the older releases as well. I am not sure, whether I am posting my query on correct page or not, apology for this.
My query is related to converting Java types to SQL types & it's related to date column for Oracle DB so thought to ask here.

Let's say, I have Date column in Oracle database table so the datatype is Date & that column has the index created. When ever we hit the database by passing the java.sql.Timestamp value in parameterized statement then that Date column is getting converted into Timestamp and which makes the indexes invalid for that Date column so this hits the performance issue. So as the workaround solution we have customized StatementCreatorUtils class & did the conversion from java.sql.Timestamp to oracle.sql.DATE if the DB type is oracle.

So can anybody please reply on this whether this is the expected behavior or am I missing something here. Reply from the experts will really help me.

I could see same topic had been discussed in past on stack overflow, adding the links here for reference.
https://stackoverflow.com/questions/6612679/non-negligible-execution-plan-difference-with-oracle-when-using-jdbc-timestamp-o
https://stackoverflow.com/questions/1945603/why-is-oracle-so-slow-when-i-pass-a-java-sql-timestamp-for-a-date-column/6620643
Thank you so much in advance.... :)

mdeinum pushed a commit to mdeinum/spring-framework that referenced this issue Jun 29, 2023
This commit adds mapping for two types from the `java.time` package,
complementing the types that are already translatable to Sql types
TIME, DATE and TIMESTAMP:
 - `OffsetTime` maps to a `TIME_WITH_TIMEZONE`
 - `OffsetDateTime` maps to a `TIMESTAMP_WITH_TIMEZONE`

This is in accordance with the B.4 table provided in the JDBC 4.2
specification.

When preparing statements, these `java.time` types use the `setObject`
method. Tests covering the 5 `java.time` classes have also been added.

See spring-projectsgh-28778
See spring-projectsgh-28527
Closes spring-projectsgh-30123
@PhilippeHaution
Copy link

PhilippeHaution commented Jul 26, 2023

In the same StatementCreatorUtils class, there is a private static void setValue(PreparedStatement ps, int paramIndex, int sqlType, @nullable String typeName, @nullable Integer scale, Object inValue) method which performs for instance:

		else if (sqlType == Types.DATE) {
			if (inValue instanceof java.util.Date) {
				if (inValue instanceof java.sql.Date) {
					ps.setDate(paramIndex, (java.sql.Date) inValue);
				}
				else {
					ps.setDate(paramIndex, new java.sql.Date(((java.util.Date) inValue).getTime()));
				}
			}
			else if (inValue instanceof Calendar) {
				Calendar cal = (Calendar) inValue;
				ps.setDate(paramIndex, new java.sql.Date(cal.getTime().getTime()), cal);
			}
			else {
				ps.setObject(paramIndex, inValue, Types.DATE);
			}
		}

So if we pass a LocalDate inValue, we actually leave it up to the driver to manage it with the ps.setObject() call. Should we not have another check of the LocalDate type that converts it into a java.sl.Date and invokes ps.setDate() instead?

			else if (inValue instanceof LocalDate) {
				LocalDate dt = (LocalDate) inValue;
				ps.setDate(paramIndex, java.sql.Date.valueOf(dt));
			}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants