Description:
Environment:
- Connector/J: 26.7.0-SNAPSHOT (trunk 559f62df, built from source)
- Reproduced on 26.7.0-SNAPSHOT; also present in 9.7.0 (same
ResultSetMetaData code, by inspection)
- MySQL Server: 8.4.11 (Podman container, image mysql:8.4)
- JDK: Temurin 1.8.0_504
- OS: Ubuntu 24.04, Linux 6.8.0-139-generic x86_64
- Connection property: treatMysqlDatetimeAsTimestamp=true
With treatMysqlDatetimeAsTimestamp=true, ResultSet.getObject() returns
java.sql.Timestamp for a DATETIME column, but
ResultSetMetaData.getColumnClassName() still returns
java.time.LocalDateTime.
This is inconsistent with the JDBC ResultSetMetaData.getColumnClassName()
contract, which describes the class returned by ResultSet.getObject().
ResultSet.getObject() may return a subclass of the class returned by
getColumnClassName(); java.sql.Timestamp is not a subclass of
java.time.LocalDateTime.
The property description says it changes the DATETIME-to-Java mapping in
ResultSet.getObject() from java.time.LocalDateTime to java.sql.Timestamp;
getColumnClassName() should describe the same mapping.
getColumnType() remains java.sql.Types.TIMESTAMP (93); only the class name
is inconsistent. With the property set to false, both calls return
java.time.LocalDateTime.
Affects 8.2.0 and later (the property was introduced in 8.2.0).
Relation to Bug#102321 (not a duplicate):
Bug#102321 fixed the default DATETIME mapping: metadata returned
java.sql.Timestamp while getObject() returned java.time.LocalDateTime. The
fix made MysqlType.DATETIME map to LocalDateTime.
This report is about the opt-in path added by Bug#107215 in 8.2.0:
treatMysqlDatetimeAsTimestamp=true makes getObject() return Timestamp, but
getColumnClassName() was not updated. The default path still satisfies the
testBug102321 invariant; the opt-in path does not.
How to repeat:
1. Use a table with a DATETIME column, for example:
CREATE TABLE t (dt DATETIME);
INSERT INTO t VALUES ('2020-01-02 03:04:05');
2. Connect with treatMysqlDatetimeAsTimestamp=true.
3. Run:
SELECT dt FROM t;
4. Compare:
rs.getObject(1).getClass().getName()
rs.getMetaData().getColumnClassName(1)
Expected result:
getObject(1) = java.sql.Timestamp
getColumnClassName(1) = java.sql.Timestamp
Actual result:
getObject(1) = java.sql.Timestamp
getColumnClassName(1) = java.time.LocalDateTime
Suggested fix:
ResultSetMetaData only receives treatYearAsDate today; DATETIME falls through to MysqlType.DATETIME.getClassName(), which is LocalDateTime.
Pass treatMysqlDatetimeAsTimestamp into ResultSetMetaData (mirroring treatYearAsDate) and return Timestamp.class.getName() for DATETIME when the property is true. Keep parameter metadata unchanged, because the property is read-side only.