From cb600be1f1c98952c2bcbdba4c4ce9108a7f4919 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sat, 14 Mar 2026 09:37:19 +0100 Subject: [PATCH] Fix nan-to-int64 crash when avg/quantile runs on empty result set ClickHouse avg() and quantile() return nan/inf on zero rows, which toInt64() cannot convert. Wrap with ifNotFinite(..., 0) to default to zero. Applied to both stats and timeseries queries. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../server/app/search/ClickHouseSearchEngine.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java index 148ba81c..4f28db1a 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java @@ -91,8 +91,8 @@ public class ClickHouseSearchEngine implements SearchEngine { public ExecutionStats stats(Instant from, Instant to) { String aggregateSql = "SELECT count() AS total_count, " + "countIf(status = 'FAILED') AS failed_count, " + - "toInt64(avg(duration_ms)) AS avg_duration_ms, " + - "toInt64(quantile(0.99)(duration_ms)) AS p99_duration_ms, " + + "toInt64(ifNotFinite(avg(duration_ms), 0)) AS avg_duration_ms, " + + "toInt64(ifNotFinite(quantile(0.99)(duration_ms), 0)) AS p99_duration_ms, " + "countIf(status = 'RUNNING') AS active_count " + "FROM route_executions WHERE start_time >= ? AND start_time <= ?"; @@ -143,8 +143,8 @@ public class ClickHouseSearchEngine implements SearchEngine { "toDateTime(intDiv(toUInt32(toDateTime(start_time)), " + intervalSeconds + ") * " + intervalSeconds + ") AS bucket, " + "count() AS total_count, " + "countIf(status = 'FAILED') AS failed_count, " + - "toInt64(avg(duration_ms)) AS avg_duration_ms, " + - "toInt64(quantile(0.99)(duration_ms)) AS p99_duration_ms, " + + "toInt64(ifNotFinite(avg(duration_ms), 0)) AS avg_duration_ms, " + + "toInt64(ifNotFinite(quantile(0.99)(duration_ms), 0)) AS p99_duration_ms, " + "countIf(status = 'RUNNING') AS active_count " + "FROM route_executions " + "WHERE start_time >= ? AND start_time <= ? " +