This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new c4762905ce91 chore: camel-clickhouse - treat an empty List body as a
0-row insert (#28986)
c4762905ce91 is described below
commit c4762905ce913111eada7cb3c7ee28bfb38af9fb
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Nov 2 22:33:26 2026 +0100
chore: camel-clickhouse - treat an empty List body as a 0-row insert
(#28986)
An empty List body was passed to Client.insert, and client-v2 fails it
with "Data cannot be empty". The producer now skips the client call for
an empty List and sets CamelClickHouseWrittenRows to 0.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../camel/catalog/docs/clickhouse-component.adoc | 1 +
.../src/main/docs/clickhouse-component.adoc | 1 +
.../component/clickhouse/ClickHouseProducer.java | 8 ++++++--
.../component/clickhouse/ClickHouseProducerTest.java | 20 +++++++++++---------
4 files changed, 19 insertions(+), 11 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/clickhouse-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/clickhouse-component.adoc
index a2a03d957ed4..e052b5bf5a62 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/clickhouse-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/clickhouse-component.adoc
@@ -63,6 +63,7 @@ types are `InputStream`, `byte[]`, `String`, `java.io.File`
(matched to the `for
whose class has been registered on the shared `Client` with
`Client.register(Class, TableSchema)`. A `List` of
`Map` is not supported: marshal the rows to the `format` (such as
`JSONEachRow`) first. When the body is a `List`
and `batchSize` is greater than 0, the list is split into batches of that
size, each sent as a separate insert.
+An empty `List` is a 0-row insert: nothing is sent to ClickHouse.
The number of written rows is set on the `CamelClickHouseWrittenRows` header.
| `query` | Runs the SQL statement contained in the message body and returns
the result set in the configured
`format`: a `String` body for text formats (such as `JSONEachRow`, `CSV` or
`TSV`), and a `byte[]` body for binary
diff --git
a/components/camel-clickhouse/src/main/docs/clickhouse-component.adoc
b/components/camel-clickhouse/src/main/docs/clickhouse-component.adoc
index a2a03d957ed4..e052b5bf5a62 100644
--- a/components/camel-clickhouse/src/main/docs/clickhouse-component.adoc
+++ b/components/camel-clickhouse/src/main/docs/clickhouse-component.adoc
@@ -63,6 +63,7 @@ types are `InputStream`, `byte[]`, `String`, `java.io.File`
(matched to the `for
whose class has been registered on the shared `Client` with
`Client.register(Class, TableSchema)`. A `List` of
`Map` is not supported: marshal the rows to the `format` (such as
`JSONEachRow`) first. When the body is a `List`
and `batchSize` is greater than 0, the list is split into batches of that
size, each sent as a separate insert.
+An empty `List` is a 0-row insert: nothing is sent to ClickHouse.
The number of written rows is set on the `CamelClickHouseWrittenRows` header.
| `query` | Runs the SQL statement contained in the message body and returns
the result set in the configured
`format`: a `String` body for text formats (such as `JSONEachRow`, `CSV` or
`TSV`), and a `byte[]` body for binary
diff --git
a/components/camel-clickhouse/src/main/java/org/apache/camel/component/clickhouse/ClickHouseProducer.java
b/components/camel-clickhouse/src/main/java/org/apache/camel/component/clickhouse/ClickHouseProducer.java
index 1dea7d1c7ac3..62816152b236 100644
---
a/components/camel-clickhouse/src/main/java/org/apache/camel/component/clickhouse/ClickHouseProducer.java
+++
b/components/camel-clickhouse/src/main/java/org/apache/camel/component/clickhouse/ClickHouseProducer.java
@@ -124,7 +124,11 @@ public class ClickHouseProducer extends DefaultProducer {
}
private long insertList(Client client, String target, List<?> data,
InsertSettings settings) throws Exception {
- if (!data.isEmpty() && data.get(0) instanceof Map) {
+ if (data.isEmpty()) {
+ // client-v2 fails on an empty list (Data cannot be empty), so an
empty list is a 0-row insert
+ return 0;
+ }
+ if (data.get(0) instanceof Map) {
throw new ClickHouseException(
"Cannot insert a List of Maps into " + target + ": a List
body must hold objects whose class is"
+ " registered on the Client with
Client.register(Class, TableSchema)."
@@ -150,7 +154,7 @@ public class ClickHouseProducer extends DefaultProducer {
future = client.insert(target, batch, settings);
} catch (NullPointerException e) {
// client-v2 throws a NullPointerException that does not say why
when no class is registered for the table
- Object first = batch.isEmpty() ? null : batch.get(0);
+ Object first = batch.get(0);
String what = first != null ? "a List of " +
first.getClass().getName() : "the List";
throw new ClickHouseException(
"Cannot insert " + what + " into " + target
diff --git
a/components/camel-clickhouse/src/test/java/org/apache/camel/component/clickhouse/ClickHouseProducerTest.java
b/components/camel-clickhouse/src/test/java/org/apache/camel/component/clickhouse/ClickHouseProducerTest.java
index e25747a17896..9c28d79cabe2 100644
---
a/components/camel-clickhouse/src/test/java/org/apache/camel/component/clickhouse/ClickHouseProducerTest.java
+++
b/components/camel-clickhouse/src/test/java/org/apache/camel/component/clickhouse/ClickHouseProducerTest.java
@@ -182,17 +182,19 @@ class ClickHouseProducerTest extends CamelTestSupport {
}
@Test
- void insertEmptyListKeepsTheClientErrorAsCause() {
- // the message must not fail on the empty batch and hide the
NullPointerException of the client
- when(client.insert(anyString(), anyList(),
any(InsertSettings.class))).thenThrow(new NullPointerException());
+ void insertEmptyListIsZeroRowInsert() throws Exception {
+ // client-v2 fails an empty list with "Data cannot be empty", so the
client must not be called
+ when(client.insert(anyString(), anyList(), any(InsertSettings.class)))
+ .thenThrow(new IllegalArgumentException("Data cannot be
empty"));
- Exchange out = template.send("direct:insert", exchange ->
exchange.getIn().setBody(List.of()));
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(1);
+ mock.expectedHeaderReceived(ClickHouseConstants.WRITTEN_ROWS, 0L);
- assertThat(out.getException())
- .isInstanceOf(ClickHouseException.class)
- .hasMessageContaining("Cannot insert the List")
- .hasMessageContaining("Client.register")
- .hasCauseInstanceOf(NullPointerException.class);
+ template.sendBody("direct:insert", List.of());
+
+ MockEndpoint.assertIsSatisfied(context);
+ verify(client, never()).insert(anyString(), anyList(),
any(InsertSettings.class));
}
@Test