Skip to content

Commit ec73677

Browse files
committed
fix: provide default getObject(Class) fallback in QueryJDBCAccessor
Replace the base-class stub that threw `Operation not supported` unconditionally with a generic raw-Object + isInstance fallback. JDBC's `ResultSet.getObject(int, Class<T>)` is documented to deliver the column value as an instance of the requested type when the conversion is trivial; pre-this-change every accessor that did not explicitly implement typed conversion would throw, even for the identity case (`getObject(col, String.class)` on a VARCHAR column). Callers had to either special-case "accessor implements typed getObject" vs "does not" or wrap the call in catch-and-retry. The new default checks for null type, fetches the raw object, returns null on null, returns the raw object cast to T when the type is assignable, and otherwise raises a typed conversion error. Accessors that need richer conversion (e.g. timestamp -> Instant / OffsetDateTime / ZonedDateTime / LocalDateTime) still override and are unaffected. Bundles `StreamingResultSetMethodTest.getObjectWithClassUsesAccessorBaseFallback` which pins the inherited path end-to-end on a VARCHAR column whose accessor does not implement typed conversion. Existing `QueryJDBCAccessorTest` continues to pass since it does not exercise `getObject(Class)`; null-type rejection is already pinned by `TimeStampVectorAccessorTest`.
1 parent dd37a96 commit ec73677

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/accessor/QueryJDBCAccessor.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,28 @@ public Reader getNCharacterStream() throws SQLException {
193193
throw getOperationNotSupported(this.getClass());
194194
}
195195

196-
@Override
197-
public <T> T getObject(Class<T> aClass) throws SQLException {
198-
throw getOperationNotSupported(aClass.getClass());
196+
/**
197+
* Default {@code getObject(Class)} implementation: take the raw object produced by
198+
* {@link #getObject()} and return it if {@code type.isInstance(raw)}, otherwise raise a
199+
* conversion error. Accessors that need richer conversion (e.g. an Arrow {@code TIMESTAMP}
200+
* vector returning {@link java.time.Instant} / {@link java.time.OffsetDateTime}) override
201+
* this; everyone else inherits this generic path so callers do not need to special-case
202+
* "accessor implements typed getObject" vs "accessor does not".
203+
*/
204+
@Override
205+
public <T> T getObject(Class<T> type) throws SQLException {
206+
if (type == null) {
207+
throw new SQLException("type parameter must not be null", "22023");
208+
}
209+
Object raw = getObject();
210+
if (raw == null) {
211+
return null;
212+
}
213+
if (type.isInstance(raw)) {
214+
return type.cast(raw);
215+
}
216+
throw new SQLException("Cannot convert column value to " + type.getName() + "; actual type is "
217+
+ raw.getClass().getName());
199218
}
200219

201220
private static SQLException getOperationNotSupported(final Class<?> type) {

jdbc-core/src/test/java/com/salesforce/datacloud/jdbc/core/StreamingResultSetMethodTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ void methodsThrowAfterClose() throws Exception {
143143
.hasMessageContaining("closed");
144144
}
145145

146+
@Test
147+
void getObjectWithClassUsesAccessorBaseFallback() throws Exception {
148+
// VarCharVectorAccessor does not override getObject(Class); it inherits the default in
149+
// QueryJDBCAccessor that does raw + isInstance. Pin that this delivers a String for a
150+
// VARCHAR column — regressing the base-class fallback breaks every accessor that does
151+
// not implement typed conversion of its own.
152+
try (val rs = createResultSet()) {
153+
rs.next();
154+
assertThat(rs.getObject(1, String.class)).isEqualTo("hello");
155+
}
156+
}
157+
146158
@Test
147159
void queryId() throws Exception {
148160
try (val rs = createResultSet()) {

0 commit comments

Comments
 (0)