Hi,
I have found a quite nasty bug. It only appears when using DB2 7.2 and
trying to map a String onto a longvarchar field: whatever length my string
had, it always was truncated at 255 characters in the database (without any
warning or error message).
note: maybe (I'd say probably) other versions of DB2 are affected, but I
haven't tested them. I've tested with SQL Server, Oracle, PostgreSQL and
MySQL and the problem doesn't occur
After investigating the problem, it appears that DB2's JDBC driver has a
"feature" other vendor's drivers dont have: when using
PreparedStatements.setObject(int parameterIndex, Object x, int
targetSqlType), the targetSqlType has to be accurate, i.e. match the type of
the field in the database.
For instance, if the field "body" is a longvarchar, then the type has to be
java.sql.Types.LONGVARCHAR.
If the type is java.sql.Types.CHAR, then the String given in parameter will
be truncated to 255 characters.
As I had the following mapping for my field:
<field name="body" type="java.lang.String">
<sql name= "BODY" type="longvarchar" dirty="ignore"/>
</field>
So, somewhere, Castor lost track of the "longvarchar" attribute, and that's
in the createFieldDesc method of the JDOMappingLoader class:
sqlType = SQLTypes.typeFromName( fieldMap.getSql().getType()[i] );
if ( _factory != null )
sqlType = _factory.adjustSqlType( sqlType );
sType[i] = SQLTypes.getSQLType( sqlType ); // -> no!
The java class corresponding to the sql type is fetched, then adjusted to
fix problems with select databases, then the sqlType is fetched from this
class. Problem is, the getSQLType method fetches the first matching SQLType
while iterating through SQLTypes._typeInfos, and that's CHAR.
I've done a quick fix to this under this form:
sqlType = SQLTypes.typeFromName( fieldMap.getSql().getType()[i] );
Class classBeforeAdjustment = sqlType;
if ( _factory != null )
sqlType = _factory.adjustSqlType( sqlType );
// quick and dirty bugFix: only use getSQLType if the class has actually
changed
// otherwise, use the sqlTypeFromName
if (sqlType != classBeforeAdjustment)
sType[i] = SQLTypes.getSQLType( sqlType );
else
sType[i] = SQLTypes.sqlTypeFromName(fieldMap.getSql().getType()[i]);
This fixes the problem, however, the solution is not satisfactory, as this
only works because the DB2 factory does not adjust the class, and thus could
eventually lead to problems with other RDBMS.
I think it would be better to have a adjustSQLType method that takes a jdbc
SQL Type as a parameter and returns the adjusted SQLType.
What do you think?
Regards,
Thierry Guerin
PS: here's the result of the CVS Diff for this class
cvs diff JDOMappingLoader.java (in directory
D:\CVS\castor\src\main\org\exolab\castor\jdo\engine)
Index: JDOMappingLoader.java
===================================================================
RCS file:
/cvs/castor/castor/src/main/org/exolab/castor/jdo/engine/JDOMappingLoader.ja
va,v
retrieving revision 1.24
diff -r1.24 JDOMappingLoader.java
254a255
> Class classBeforeAdjustment = sqlType;
257c258,263
< sType[i] = SQLTypes.getSQLType( sqlType );
---
> // quick and dirty bugFix: only use getSQLType if the
>class has
actually changed
> // otherwise, use the sqlTypeFromName
> if (sqlType != classBeforeAdjustment)
> sType[i] = SQLTypes.getSQLType( sqlType );
> else
> sType[i] =
>SQLTypes.sqlTypeFromName(fieldMap.getSql().getType()[i]);
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev