fix(intersystems): read out-of-range integers via BigDecimal

This commit is contained in:
Eve authored and GitHub committed 2026-09-08 12:47:44 +08:00
1 parent 4c0ca9293a
commit 47e41bb48a
4 files changed
+94 -8

No files matched your search

@@ -42,10 +42,22 @@ public final class CacheAgent extends ConfiguredJdbcAgent {
@Override
protected Object resultValue(ResultSet rs, int index, int sqlType) {
if (sqlType == Types.OTHER) {
return unchecked(() -> JdbcExecutor.normalizeResultValue(rs.getObject(index)));
switch (sqlType) {
case Types.BIGINT:
case Types.INTEGER:
case Types.SMALLINT:
case Types.TINYINT:
// Caché can expose values outside the Java primitive range
// implied by its JDBC metadata. Preserve them without narrowing.
return unchecked(() -> {
Object value = rs.getBigDecimal(index);
return rs.wasNull() ? null : value;
});
case Types.OTHER:
return unchecked(() -> JdbcExecutor.normalizeResultValue(rs.getObject(index)));
default:
return super.resultValue(rs, index, sqlType);
}
return super.resultValue(rs, index, sqlType);
}
@Override
@@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
@@ -88,8 +89,38 @@ class CacheAgentTest {
assertEquals(Collections.singletonList("getObject"), calls);
}
@Test
void readsOutOfRangeIntegerThroughBigDecimal() {
BigDecimal valueOutsideIntegerRange = new BigDecimal("2147483648");
List<String> calls = new ArrayList<>();
ResultSet resultSet = proxy(ResultSet.class, (method, args) -> {
if ("getBigDecimal".equals(method.getName())) {
calls.add("getBigDecimal");
return valueOutsideIntegerRange;
}
if (method.getName().startsWith("get")) {
calls.add(method.getName());
throw new SQLException("Numeric value out of range");
}
if ("wasNull".equals(method.getName())) {
return false;
}
return defaultValue(method.getReturnType());
});
Object value = new CacheAgent().resultValue(resultSet, 1, Types.INTEGER);
assertEquals(valueOutsideIntegerRange, value);
assertEquals(Collections.singletonList("getBigDecimal"), calls);
}
@Test
void preservesStringPathForStandardValues() {
assertStringPath(Types.VARCHAR);
assertStringPath(Types.LONGVARCHAR);
}
private static void assertStringPath(int sqlType) {
List<String> calls = new ArrayList<>();
ResultSet resultSet = proxy(ResultSet.class, (method, args) -> {
if ("getString".equals(method.getName())) {
@@ -102,7 +133,7 @@ class CacheAgentTest {
return defaultValue(method.getReturnType());
});
Object value = new CacheAgent().resultValue(resultSet, 1, Types.VARCHAR);
Object value = new CacheAgent().resultValue(resultSet, 1, sqlType);
assertEquals("ordinary", value);
assertEquals(Collections.singletonList("getString"), calls);