"getResultSet not implemented" error when mapping Array(Nullable(UInt32)) after updating from 0.3.2-patch11
Describe the bug
Upon trying to update from 0.3.2-patch11 to 0.6.0-patch1:http, some behavior changes were noticed regarding the mapping of Array(Nullable(UInt32)) data type when using JDBI. The previous code used to work correctly, but it started to throw a getResultSet not implemented after updating the clickhouse dependency. It seems to have started at the 0.4.0 version.
Upon further investigation, it was observed that Array(Nullable(UInt32)) is now being mapped to an array of UnsignedInteger, instead of to Long. That can be seen inspecting JDBI's buildArray method. That ends up trying to use the resultSet, which is not implemented in the clickhouse dependency.
It was also noticed thatNullable(UInt32) is still being mapped to Long, the same as before.
Is that behavior change expected?
Steps to reproduce
- Insert
Array(Nullable(UInt32))data into some clickhouse table - Retrieve
Array(Nullable(UInt32))data using JDBI
Expected behavior
Array(Nullable(UInt32)) should be mapped to Long[].
Code example
build.gradle with used dependencies
plugins {
id("io.micronaut.application") version "4.2.1"
}
version = "0.1"
group = "com.example"
repositories {
mavenCentral()
}
ext {
micronautVersion = '4.2.3'
}
dependencies {
annotationProcessor "org.projectlombok:lombok:1.18.30"
compileOnly "org.projectlombok:lombok:1.18.30"
implementation "org.jdbi:jdbi3-sqlobject:3.44.0"
implementation "com.clickhouse:clickhouse-jdbc:0.6.0-patch1:http"
implementation 'org.apache.httpcomponents.client5:httpclient5:5.3.1'
runtimeOnly "io.micronaut.sql:micronaut-jdbc-hikari"
runtimeOnly "org.yaml:snakeyaml"
}
java {
sourceCompatibility = JavaVersion.toVersion("21")
targetCompatibility = JavaVersion.toVersion("21")
}
micronaut {
testRuntime("junit5")
processing {
incremental(true)
annotations("com.example.*")
}
}
Sample Bean
package com.example.dao.dto;
import lombok.Value;
@Value
public class SampleArrayDto {
String id;
Long[] uint32Array;
}
Sample DAO
package com.example.dao.clickhouse;
import com.example.dao.dto.SampleArrayDto;
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import java.util.List;
public interface SampleArrayDao {
@SqlUpdate("INSERT INTO sample_array (id, uint32_array) VALUES (:id, :uint32Array::Array(Nullable(UInt32)))")
void insert(@BindBean SampleArrayDto sampleArrayDto);
@SqlQuery("SELECT * FROM sample_array")
@RegisterConstructorMapper(SampleArrayDto.class)
List<SampleArrayDto> getAll();
@SqlUpdate("TRUNCATE TABLE sample_array")
void truncate();
}
Jdbi Factory
package com.example.factory;
import io.micronaut.context.annotation.Factory;
import jakarta.inject.Singleton;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import javax.sql.DataSource;
@Factory
public class JdbiFactory {
@Singleton
Jdbi newClickhouseJdbi(DataSource dataSource) {
Jdbi jdbi = Jdbi.create(dataSource);
jdbi.installPlugin(new SqlObjectPlugin());
return jdbi;
}
}
DAO Factory
package com.example.factory;
import com.example.dao.clickhouse.SampleArrayDao;
import io.micronaut.context.annotation.Factory;
import jakarta.inject.Singleton;
import org.jdbi.v3.core.Jdbi;
@Factory
public class ClickhouseDaoFactory {
@Singleton
SampleArrayDao getSampleArrayDao(Jdbi jdbi) {
return jdbi.onDemand(SampleArrayDao.class);
}
}
Test that reproduces the issue
package com.example.dao.clickhouse;
import com.example.dao.dto.SampleArrayDto;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@MicronautTest
class SampleArrayDaoTest {
@Inject private SampleArrayDao sampleArrayDao;
@BeforeEach
@AfterEach
void clearTable() {
sampleArrayDao.truncate();
}
@Test
void getAll() {
var sampleArrayDto = new SampleArrayDto("1", new Long[]{10L});
sampleArrayDao.insert(sampleArrayDto);
sampleArrayDao.getAll(); // In this line the issue happens
}
}
application.yml with datasource configuration
datasources:
clickhouse:
url: "jdbc:ch://localhost:8123/default"
username: default
driverClassName: com.clickhouse.jdbc.ClickHouseDriver
(Whole sample project can be uploaded if that helps)
Error log
Exception thrown mapping result set into return type [statement:"SELECT * FROM sample_array", arguments:{positional:{}, named:{}, finder:[]}]
org.jdbi.v3.core.result.ResultSetException: Exception thrown mapping result set into return type [statement:"SELECT * FROM sample_array", arguments:{positional:{}, named:{}, finder:[]}]
at org.jdbi.v3.core.result.internal.ResultSetResultIterator.next(ResultSetResultIterator.java:102)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at org.jdbi.v3.core.result.ResultIterator.forEachRemaining(ResultIterator.java:39)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1939)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at org.jdbi.v3.core.result.ResultIterable.collect(ResultIterable.java:341)
at org.jdbi.v3.sqlobject.statement.internal.ResultReturner$CollectedResultReturner.mappedResult(ResultReturner.java:315)
at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.lambda$configureReturner$0(SqlQueryHandler.java:65)
at org.jdbi.v3.sqlobject.statement.internal.CustomizingStatementHandler.invoke(CustomizingStatementHandler.java:197)
at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.invoke(SqlQueryHandler.java:27)
at org.jdbi.v3.core.extension.ExtensionMetadata$ExtensionHandlerInvoker.lambda$invoke$0(ExtensionMetadata.java:345)
at org.jdbi.v3.core.AbstractHandleSupplier.invokeInContext(AbstractHandleSupplier.java:36)
at org.jdbi.v3.core.extension.ExtensionMetadata$ExtensionHandlerInvoker.call(ExtensionMetadata.java:363)
at org.jdbi.v3.core.extension.ExtensionMetadata$ExtensionHandlerInvoker.invoke(ExtensionMetadata.java:346)
at org.jdbi.v3.core.extension.ExtensionFactoryDelegate.lambda$attach$0(ExtensionFactoryDelegate.java:118)
at org.jdbi.v3.core.internal.OnDemandExtensions.invoke(OnDemandExtensions.java:85)
at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$createProxy$2(OnDemandExtensions.java:71)
at org.jdbi.v3.core.Jdbi.callWithExtension(Jdbi.java:560)
at org.jdbi.v3.core.Jdbi.withExtension(Jdbi.java:547)
at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$createProxy$3(OnDemandExtensions.java:71)
at jdk.proxy3/jdk.proxy3.$Proxy27.getAll(Unknown Source)
at com.example.dao.clickhouse.SampleArrayDaoTest.getAll(SampleArrayDaoTest.java:25)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at io.micronaut.test.extensions.junit5.MicronautJunit5Extension$2.proceed(MicronautJunit5Extension.java:142)
at io.micronaut.test.extensions.AbstractMicronautExtension.interceptEach(AbstractMicronautExtension.java:157)
at io.micronaut.test.extensions.AbstractMicronautExtension.interceptTest(AbstractMicronautExtension.java:114)
at io.micronaut.test.extensions.junit5.MicronautJunit5Extension.interceptTestMethod(MicronautJunit5Extension.java:129)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.sql.SQLFeatureNotSupportedException: getResultSet not implemented
at com.clickhouse.jdbc.SqlExceptionUtils.unsupportedError(SqlExceptionUtils.java:152)
at com.clickhouse.jdbc.ClickHouseArray.getResultSet(ClickHouseArray.java:73)
at org.jdbi.v3.core.array.ArrayColumnMapper.buildFromResultSet(ArrayColumnMapper.java:74)
at org.jdbi.v3.core.array.ArrayColumnMapper.buildArray(ArrayColumnMapper.java:69)
at org.jdbi.v3.core.array.ArrayColumnMapper.map(ArrayColumnMapper.java:47)
at org.jdbi.v3.core.mapper.SingleColumnMapper.lambda$new$0(SingleColumnMapper.java:41)
at org.jdbi.v3.core.mapper.SingleColumnMapper.map(SingleColumnMapper.java:55)
at org.jdbi.v3.core.mapper.reflect.ConstructorMapper$BoundConstructorMapper.map(ConstructorMapper.java:381)
at org.jdbi.v3.core.result.internal.ResultSetResultIterator.next(ResultSetResultIterator.java:100)
... 32 more
getResultSet not implemented
java.sql.SQLFeatureNotSupportedException: getResultSet not implemented
at com.clickhouse.jdbc.SqlExceptionUtils.unsupportedError(SqlExceptionUtils.java:152)
at com.clickhouse.jdbc.ClickHouseArray.getResultSet(ClickHouseArray.java:73)
at org.jdbi.v3.core.array.ArrayColumnMapper.buildFromResultSet(ArrayColumnMapper.java:74)
at org.jdbi.v3.core.array.ArrayColumnMapper.buildArray(ArrayColumnMapper.java:69)
at org.jdbi.v3.core.array.ArrayColumnMapper.map(ArrayColumnMapper.java:47)
at org.jdbi.v3.core.mapper.SingleColumnMapper.lambda$new$0(SingleColumnMapper.java:41)
at org.jdbi.v3.core.mapper.SingleColumnMapper.map(SingleColumnMapper.java:55)
at org.jdbi.v3.core.mapper.reflect.ConstructorMapper$BoundConstructorMapper.map(ConstructorMapper.java:381)
at org.jdbi.v3.core.result.internal.ResultSetResultIterator.next(ResultSetResultIterator.java:100)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at org.jdbi.v3.core.result.ResultIterator.forEachRemaining(ResultIterator.java:39)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1939)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at org.jdbi.v3.core.result.ResultIterable.collect(ResultIterable.java:341)
at org.jdbi.v3.sqlobject.statement.internal.ResultReturner$CollectedResultReturner.mappedResult(ResultReturner.java:315)
at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.lambda$configureReturner$0(SqlQueryHandler.java:65)
at org.jdbi.v3.sqlobject.statement.internal.CustomizingStatementHandler.invoke(CustomizingStatementHandler.java:197)
at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.invoke(SqlQueryHandler.java:27)
at org.jdbi.v3.core.extension.ExtensionMetadata$ExtensionHandlerInvoker.lambda$invoke$0(ExtensionMetadata.java:345)
at org.jdbi.v3.core.AbstractHandleSupplier.invokeInContext(AbstractHandleSupplier.java:36)
at org.jdbi.v3.core.extension.ExtensionMetadata$ExtensionHandlerInvoker.call(ExtensionMetadata.java:363)
at org.jdbi.v3.core.extension.ExtensionMetadata$ExtensionHandlerInvoker.invoke(ExtensionMetadata.java:346)
at org.jdbi.v3.core.extension.ExtensionFactoryDelegate.lambda$attach$0(ExtensionFactoryDelegate.java:118)
at org.jdbi.v3.core.internal.OnDemandExtensions.invoke(OnDemandExtensions.java:85)
at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$createProxy$2(OnDemandExtensions.java:71)
at org.jdbi.v3.core.Jdbi.callWithExtension(Jdbi.java:560)
at org.jdbi.v3.core.Jdbi.withExtension(Jdbi.java:547)
at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$createProxy$3(OnDemandExtensions.java:71)
at jdk.proxy3/jdk.proxy3.$Proxy27.getAll(Unknown Source)
at com.example.dao.clickhouse.SampleArrayDaoTest.getAll(SampleArrayDaoTest.java:25)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at io.micronaut.test.extensions.junit5.MicronautJunit5Extension$2.proceed(MicronautJunit5Extension.java:142)
at io.micronaut.test.extensions.AbstractMicronautExtension.interceptEach(AbstractMicronautExtension.java:157)
at io.micronaut.test.extensions.AbstractMicronautExtension.interceptTest(AbstractMicronautExtension.java:114)
at io.micronaut.test.extensions.junit5.MicronautJunit5Extension.interceptTestMethod(MicronautJunit5Extension.java:129)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Configuration
Environment
- Client version: 0.6.0-patch1
- Language version: 21.0.2
- OS: Ubuntu 22.04.2 LTS
ClickHouse server
- ClickHouse Server version:
altinity/clickhouse-server:23.3.8.22.altinitystable CREATE TABLEstatements for tables involved:
CREATE TABLE IF NOT EXISTS sample_array
(
id String,
uint32_array Array(Nullable(UInt32))
)
ENGINE = ReplacingMergeTree()
ORDER BY (id)