I have a simple SQL query using an aliased column: select defs.id as definition_id from definitions defs where defs.name = ?
This works fine using either Hypersonic 1.8.0.10 or the MySQL JDBC driver version 5.0.8 in conjunction with Hibernate. However, upgrading either driver [Hypersonic 1.8.1.1, MySQL 5.1.10] leads to the following type of error when the query is executed:
Caused by: java.sql.SQLException: Column not found: id at org.hsqldb.jdbc.Util.sqlException(Unknown Source) at org.hsqldb.jdbc.Util.sqlException(Unknown Source) at org.hsqldb.jdbc.jdbcResultSet.findColumn(Unknown Source) at org.hsqldb.jdbc.jdbcResultSet.getBigDecimal(Unknown Source) at org.apache.commons.dbcp.DelegatingResultSet.getBigDecimal(DelegatingResultSet.java:304) at org.hibernate.type.BigIntegerType.get(BigIntegerType.java:34) at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163) at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:189) at org.hibernate.loader.custom.CustomLoader$ScalarResultColumnProcessor.extract(CustomLoader.java:474) at org.hibernate.loader.custom.CustomLoader$ResultRowProcessor.buildResultRow(CustomLoader.java:420) at org.hibernate.loader.custom.CustomLoader.getResultColumnOrRow(CustomLoader.java:317) at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:606) at org.hibernate.loader.Loader.doQuery(Loader.java:701) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236) at org.hibernate.loader.Loader.doList(Loader.java:2213) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104) at org.hibernate.loader.Loader.list(Loader.java:2099) at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:289) at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1695) at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142) at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:152)
After doing some digging, it looks like the problem is within the CustomLoader and its use of getColumnName() when checking the metadata in order to determine the alias. To my layman's eyes, it looks like the Hibernate implementation is getting caught by newer drivers adhering to the JDBC 4.0 spec.
Here is a snippet from a MySQL list on the topic: -- BEGIN SNIPPET -- By default, we follow the JDBC Specification here, in that the 4.0 behavior is correct. Calling programs should use ResultSetMetaData.getColumnLabel() to dynamically determine the correct "name" to pass to ResultSet.findColumn() or ResultSet.get... (String) whether or not the query specifies an alias via "AS" for the column. ResultSetMetaData.getColumnName() will return the actual name of the column, if it exists, and this name can *not* be used as input to ResultSet.findColumn() or ResultSet.get...(String). The JDBC-3.0 (and earlier) specification has a bug, but you can get the buggy behavior (allowing column names *and* labels to be used for ResultSet.findColumn() and get...(String)) by setting "useColumnNamesInFindColumn" to "true". -- END SNIPPET --
For what it's worth, Hypersonic also has a property that can be used to get the old behavior. However, if the Hibernate implementation were to follow the rough outline provided by the MySQL team, would that not continue to provide support for older drivers as well as new without requiring anyone to dig around looking for property-based solutions? Is an enhancement/bug request in order?
|