From 8e6f8e2693e9be53c1e3e6f8943798459316720b Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sun, 15 Mar 2026 11:10:40 +0100 Subject: [PATCH] Fix bucket alignment: compute 5-min floor in Java, not ClickHouse SQL JDBC sends Timestamp params as strings, causing toStartOfFiveMinutes() to fail with 'Illegal type String'. Floor to 5-minute boundaries in Java instead and pass plain bucket >= ? comparisons. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/search/ClickHouseSearchEngine.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 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 24234d3e..bbd36d1f 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 @@ -99,8 +99,8 @@ public class ClickHouseSearchEngine implements SearchEngine { // Current period — read from rollup var conditions = new ArrayList(); var params = new ArrayList(); - conditions.add("bucket >= toStartOfFiveMinutes(?)"); - params.add(Timestamp.from(from)); + conditions.add("bucket >= ?"); + params.add(Timestamp.from(floorToFiveMinutes(from))); conditions.add("bucket <= ?"); params.add(Timestamp.from(to)); addScopeFilters(routeId, agentIds, conditions, params); @@ -139,8 +139,8 @@ public class ClickHouseSearchEngine implements SearchEngine { Instant prevTo = prevFrom.plus(window); var prevConditions = new ArrayList(); var prevParams = new ArrayList(); - prevConditions.add("bucket >= toStartOfFiveMinutes(?)"); - prevParams.add(Timestamp.from(prevFrom)); + prevConditions.add("bucket >= ?"); + prevParams.add(Timestamp.from(floorToFiveMinutes(prevFrom))); prevConditions.add("bucket <= ?"); prevParams.add(Timestamp.from(prevTo)); addScopeFilters(routeId, agentIds, prevConditions, prevParams); @@ -165,8 +165,8 @@ public class ClickHouseSearchEngine implements SearchEngine { Instant todayStart = Instant.now().truncatedTo(java.time.temporal.ChronoUnit.DAYS); var todayConditions = new ArrayList(); var todayParams = new ArrayList(); - todayConditions.add("bucket >= toStartOfFiveMinutes(?)"); - todayParams.add(Timestamp.from(todayStart)); + todayConditions.add("bucket >= ?"); + todayParams.add(Timestamp.from(floorToFiveMinutes(todayStart))); addScopeFilters(routeId, agentIds, todayConditions, todayParams); String todayWhere = " WHERE " + String.join(" AND ", todayConditions); @@ -194,8 +194,8 @@ public class ClickHouseSearchEngine implements SearchEngine { var conditions = new ArrayList(); var params = new ArrayList(); - conditions.add("bucket >= toStartOfFiveMinutes(?)"); - params.add(Timestamp.from(from)); + conditions.add("bucket >= ?"); + params.add(Timestamp.from(floorToFiveMinutes(from))); conditions.add("bucket <= ?"); params.add(Timestamp.from(to)); addScopeFilters(routeId, agentIds, conditions, params); @@ -326,6 +326,14 @@ public class ClickHouseSearchEngine implements SearchEngine { } } + /** + * Floor an Instant to the start of its 5-minute bucket. + */ + private static Instant floorToFiveMinutes(Instant instant) { + long epochSecond = instant.getEpochSecond(); + return Instant.ofEpochSecond(epochSecond - (epochSecond % 300)); + } + /** * Escape special LIKE characters to prevent LIKE injection. */