When indexing a table containing a version column (defined for mirroring) in a JDBC implementation of compass, the following error occurs:
"Failed to index database; nested exception is java.lang.ClassCastException: java.math.BigDecimal"
This occurs even though the version column is defined as a NUMBER(6) type and not a decimal, yet something in compass or perhaps the driver is interpreting that column as a decimal. When I utilize the Oracle native driver, the indexing issue does not occur but then mirroring is not supported due to unsupported JDBC 3.0 features (see forum thread at http://forums.opensymphony.com/thread.jspa?messageID=230914
). As a result, this issue is extremely critical as users cannot utilize mirroring for JDBC implementations of compass with Oracle databases (unless there is a known workaround, which I could not find in the forums).
My temporary "hack," which is by no means a permanent solution, was to update the org.compass.gps.device.jdbc.dialect.DefaultJDBCDialect class:
1) protected Long getLong(ResultSet rs, ColumnMapping columnMapping)
// Added support for BigDecimal type
...
if(rs.getObject(columnMapping.getColumnName()) instanceof BigDecimal)
return Long.valueOf( ((BigDecimal) rs.getObject(columnMapping.getColumnName())).longValue() );
...
2) public void setParameter(PreparedStatement ps, int paramIndex, String value)
// Added support for Types.DECIMAL:
...
if (type == Types.BIGINT || type == Types.DECIMAL) {
long lValue = Long.parseLong(value);
ps.setLong(paramIndex, lValue);
}
...
I'm trying to use Jdbc mirroring in a Oracle DB using the pseudo-column ORA_ROWSCN, so I added a version mapping with this column name.
The problem is that ORA_ROWSCN has a sqlType of -5 (Types.BIGINT) and in DefaultJdbcDialect.getVersion method lacks
the if and subsequent correct parsing for that sql type to Java BigDecimal.
This results in entering in the final else where the BigDecimal will be casted to Long (in getLong method), giving a ClassCastException.
Please add the missing else if for Type.BIGINT. Thanks.
As a workaround I extended the DefaultJdbcDialect as below and set the "dialect" property in the ResultSetJdbcGpsDevice instance with this new class.
public class IndexerDefaultJdbcDialect extends DefaultJdbcDialect {
protected Long getBigIntAsLong(final ResultSet rs, final ColumnMapping columnMapping) throws SQLException {
if (columnMapping.isUsingColumnIndex()) { return Long.valueOf(rs.getBigDecimal(columnMapping.getColumnIndex()).longValue()); }
return Long.valueOf(rs.getLong(columnMapping.getColumnName()));
}
/**
*/
@Override
public Long getVersion(final ResultSet rs, final VersionColumnMapping versionMapping) throws SQLException
}