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

Reply via email to