Mapping of non-existent columns causes error when defining ResultMaps
---------------------------------------------------------------------
Key: IBATIS-476
URL: https://issues.apache.org/jira/browse/IBATIS-476
Project: iBatis for Java
Issue Type: Improvement
Components: SQL Maps
Affects Versions: 2.3.0
Environment: Windows XP / JBoss 4.0.5 / Oracle / Teradata
Reporter: Adam Parrish
Fix For: 2.3.1
I defined the following resultMap
<resultMap
id="StatusResult"
class="mil.af.gcssdsrf.led.lims.dto.StatusRow"
>
<result property="reportingDate" column="reportingDate"
javaType="java.util.Date" jdbcType="DATE"/>
<result property="grouping" resultMap="StatusRow.GroupResult"/>
<result property="mcHours" column="mcHours"/>
<result property="fmcHours" column="fmcHours"/>
<result property="pmcHours" column="pmcHours"/>
<result property="nmcmHours" column="nmcmHours"/>
<result property="nmcbHours" column="nmcbHours"/>
<result property="tnmcmHours" column="tnmcmHours"/>
<result property="nmcsHours" column="nmcsHours"/>
<result property="tnmcsHours" column="tnmcsHours"/>
<result property="possessedHours" column="possessedHours"/>
<result property="tpmcsHours" column="tpmcsHours"/>
<result property="tnmcHours" column="tnmcHours"/>
<result property="tpmcmHours" column="tpmcmHours"/>
<result property="mcRate" column="mcRate"/>
<result property="fmcRate" column="fmcRate"/>
<result property="pmcRate" column="pmcRate"/>
<result property="nmcmRate" column="nmcmRate"/>
<result property="nmcsRate" column="nmcsRate"/>
<result property="nmcbRate" column="nmcbRate"/>
<result property="tnmcmRate" column="tnmcmRate"/>
<result property="tnmcsRate" column="tnmcsRate"/>
<result property="tpmcsRate" column="tpmcsRate"/>
<result property="tnmcRate" column="tnmcRate"/>
<result property="tpmcmRate" column="tpmcmRate"/>
</resultMap>
<resultMap
id="GroupResult"
class="mil.af.gcssdsrf.led.lims.dto.Group"
>
<result property="airForceGrouping" column="leadCommand"/>
<result property="theater" column="theater"/>
<result property="command" column="command"/>
<result property="organization" column="organization"/>
<result property="types" column="familyType"/>
<result property="designs" column="design"/>
<result property="serieses" column="series"/>
</resultMap>
When I do the following query:
<select
id="status"
resultMap="StatusResult"
parameterClass="mil.af.gcssdsrf.led.lims.service.request.FilteredAndGroupedRequest"
remapResults="true">
SELECT
<isNotNull property="grouping" removeFirstPrepend="true">
<isEqual prepend=","
property="grouping.groupByStartDate" compareValue="true">
reportingDate
</isEqual>
<isEqual prepend=","
property="grouping.groupByAirforceGrouping" compareValue="true">
leadCommand
</isEqual>
<isEqual prepend="," property="grouping.groupByTheater"
compareValue="true">
theater
</isEqual>
<isEqual prepend="," property="grouping.groupByCommand"
compareValue="true">
command
</isEqual>
<isEqual prepend=","
property="grouping.groupByOrganization" compareValue="true">
organization
</isEqual>
<isEqual prepend="," property="grouping.groupByType"
compareValue="true">
familyType
</isEqual>
<isEqual prepend="," property="grouping.groupByDesign"
compareValue="true">
design
</isEqual>
<isEqual prepend="," property="grouping.groupBySeries"
compareValue="true">
series
</isEqual>
</isNotNull>
,sum(mcHours) as mcHours,
sum(fmcHours) as fmcHours,
sum(pmcHours) as pmcHours,
sum(nmcmHours) as nmcmHours,
sum(nmcbHours) as nmcbHours,
sum(tnmcmHours) as tnmcmHours,
sum(nmcsHours) as nmcsHours,
sum(tnmcsHours) as tnmcsHours,
sum(possessedHours) as possessedHours,
sum(tpmcsHours) as tpmcsHours,
sum(tnmcHours) as tnmcHours,
sum(tpmcmHours) as tpmcmHours,
sum(mcHours) / sum(possessedHours) as mcRate,
sum(fmcHours) / sum(possessedHours)as fmcRate,
sum(pmcHours) / sum(possessedHours)as pmcRate,
sum(nmcmHours) / sum(possessedHours)as nmcmRate,
sum(nmcsHours) / sum(possessedHours)as nmcsRate,
sum(nmcbHours) / sum(possessedHours)as nmcbRate,
sum(tnmcmHours) / sum(possessedHours)as tnmcmRate,
sum(tnmcsHours) / sum(possessedHours)as tnmcsRate,
sum(tpmcsHours) / sum(possessedHours)as tpmcsRate,
sum(tnmcHours) / sum(possessedHours)as tnmcRate,
sum(tpmcmHours) / sum(possessedHours)as tpmcmRate
FROM status_table
GROUP BY
<isNotNull property="grouping" removeFirstPrepend="true">
<isEqual prepend=","
property="grouping.groupByStartDate" compareValue="true">
reportingDate
</isEqual>
<isEqual prepend=","
property="grouping.groupByAirforceGrouping" compareValue="true">
leadCommand
</isEqual>
<isEqual prepend="," property="grouping.groupByTheater"
compareValue="true">
theater
</isEqual>
<isEqual prepend="," property="grouping.groupByCommand"
compareValue="true">
command
</isEqual>
<isEqual prepend=","
property="grouping.groupByOrganization" compareValue="true">
organization
</isEqual>
<isEqual prepend="," property="grouping.groupByType"
compareValue="true">
familyType
</isEqual>
<isEqual prepend="," property="grouping.groupByDesign"
compareValue="true">
design
</isEqual>
<isEqual prepend="," property="grouping.groupBySeries"
compareValue="true">
series
</isEqual>
</isNotNull>
ORDER BY
<isNotNull property="grouping" removeFirstPrepend="true">
<isEqual prepend=","
property="grouping.groupByStartDate" compareValue="true">
reportingDate
</isEqual>
<isEqual prepend=","
property="grouping.groupByAirforceGrouping" compareValue="true">
leadCommand
</isEqual>
<isEqual prepend="," property="grouping.groupByTheater"
compareValue="true">
theater
</isEqual>
<isEqual prepend="," property="grouping.groupByCommand"
compareValue="true">
command
</isEqual>
<isEqual prepend=","
property="grouping.groupByOrganization" compareValue="true">
organization
</isEqual>
<isEqual prepend="," property="grouping.groupByType"
compareValue="true">
familyType
</isEqual>
<isEqual prepend="," property="grouping.groupByDesign"
compareValue="true">
design
</isEqual>
<isEqual prepend="," property="grouping.groupBySeries"
compareValue="true">
series
</isEqual>
</isNotNull>
</select>
I sometimes will receive exceptions because the type handlers attempt to load a
column from the result set regardless of the fact that it doesn't exist. My
impression was that this was a reason to turn on remapResults=true, but that
functionality did not operate as expected.
My solution was to modify the type handlers in your code and rebuild the jar.
The following files were affected in my code
C:\Documents and Settings\aparrish\flex3workspaces\majcom\iBatisMapper>svn stat
M src\com\ibatis\sqlmap\engine\type\StringTypeHandler.java
M src\com\ibatis\sqlmap\engine\type\BaseTypeHandler.java
M src\com\ibatis\sqlmap\engine\type\DateTypeHandler.java
M src\com\ibatis\sqlmap\engine\type\DateOnlyTypeHandler.java
The following lines change
C:\Documents and Settings\aparrish\flex3workspaces\majcom\iBatisMapper>svn diff
Index: src/com/ibatis/sqlmap/engine/type/StringTypeHandler.java
===================================================================
--- src/com/ibatis/sqlmap/engine/type/StringTypeHandler.java (revision 601753
)
+++ src/com/ibatis/sqlmap/engine/type/StringTypeHandler.java (working copy)
@@ -32,12 +32,16 @@
public Object getResult(ResultSet rs, String columnName)
throws SQLException {
- Object s = rs.getString(columnName);
- if (rs.wasNull()) {
- return null;
- } else {
- return s;
- }
+ if(columnExists(rs, columnName)) {
+ Object s = rs.getString(columnName);
+ if (rs.wasNull()) {
+ return null;
+ } else {
+ return s;
+ }
+ } else {
+ return null;
+ }
}
public Object getResult(ResultSet rs, int columnIndex)
Index: src/com/ibatis/sqlmap/engine/type/BaseTypeHandler.java
===================================================================
--- src/com/ibatis/sqlmap/engine/type/BaseTypeHandler.java (revision 601753
)
+++ src/com/ibatis/sqlmap/engine/type/BaseTypeHandler.java (working copy)
@@ -15,11 +15,25 @@
*/
package com.ibatis.sqlmap.engine.type;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
/**
* Base type handler for convenience
*/
public abstract class BaseTypeHandler implements TypeHandler {
+
+ protected boolean columnExists(ResultSet rs, String columnName) {
+ try {
+ rs.findColumn(columnName);
+ return true;
+ } catch (SQLException e) {
+ System.out.println("Column wasn't found, swallowing exception"
);
+ return false;
+ }
+ }
+
public boolean equals(Object object, String string) {
if (object == null || string == null) {
return object == string;
Index: src/com/ibatis/sqlmap/engine/type/DateTypeHandler.java
===================================================================
--- src/com/ibatis/sqlmap/engine/type/DateTypeHandler.java (revision 601753
)
+++ src/com/ibatis/sqlmap/engine/type/DateTypeHandler.java (working copy)
@@ -35,12 +35,16 @@
public Object getResult(ResultSet rs, String columnName)
throws SQLException {
- java.sql.Timestamp sqlTimestamp = rs.getTimestamp(columnName);
- if (rs.wasNull()) {
- return null;
- } else {
- return new java.util.Date(sqlTimestamp.getTime());
- }
+ if(columnExists(rs, columnName)) {
+ java.sql.Timestamp sqlTimestamp = rs.getTimestamp(columnName);
+ if (rs.wasNull()) {
+ return null;
+ } else {
+ return new java.util.Date(sqlTimestamp.getTime());
+ }
+ } else {
+ return null;
+ }
}
public Object getResult(ResultSet rs, int columnIndex)
Index: src/com/ibatis/sqlmap/engine/type/DateOnlyTypeHandler.java
===================================================================
--- src/com/ibatis/sqlmap/engine/type/DateOnlyTypeHandler.java (revision 601753
)
+++ src/com/ibatis/sqlmap/engine/type/DateOnlyTypeHandler.java (working copy)
@@ -35,12 +35,16 @@
public Object getResult(ResultSet rs, String columnName)
throws SQLException {
- java.sql.Date sqlDate = rs.getDate(columnName);
- if (rs.wasNull()) {
- return null;
- } else {
- return new java.util.Date(sqlDate.getTime());
- }
+ if(columnExists(rs, columnName)) {
+ java.sql.Date sqlDate = rs.getDate(columnName);
+ if (rs.wasNull()) {
+ return null;
+ } else {
+ return new java.util.Date(sqlDate.getTime());
+ }
+ } else {
+ return null;
+ }
}
public Object getResult(ResultSet rs, int columnIndex)
Is there any reason to believe that this is something that others would want to
use, or a more elegant way to solve this problem to plugin to the iBatis
framework. This solution works for my needs, but is there a way to configure
this functionality so that others could leverage it if need be.
Alternatively is this functionality already built in and I am using something
improperly?
Thanks for your time and please let me know if someone wants me to help
contribute back.
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.