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.