Repository navigation
Add TOP, BOTTOM and SAMPLE; fix subqueries over aggregates - #127
Conversation
- top(), bottom() and sample() were unsupported ("unsupported aggregate
function"). They now return up to N stored points per group (GROUP BY
time() bucket and tags), each at its own time, in time order; top and
bottom take tag arguments (one point per combination), and other fields
or tags may be selected beside them. Combined with another function they
fail as in InfluxDB. On a sharded measurement each region returns its own
N per group and the coordinator ranks the union again, then applies LIMIT
and OFFSET.
- A subquery over an aggregate failed: the inner bucket was renamed to
`time` inside its own SQL, so ClickHouse read `time` in its GROUP BY as the
bucket (NOT_AN_AGGREGATE), and an inner aggregate without buckets had no
`time` at all. The inner query is now wrapped and exposes `time`: the
bucket, a lone selector's point time, or the query's lower bound.
- On a sharded measurement the gathered inner rows exposed only `__time`
(a string or the client's epoch unit), so any outer query on time failed.
They now carry a real `time` column.
- A raw field with GROUP BY time() returns InfluxDB's "GROUP BY requires at
least one aggregate function" instead of a chDB error.
PR SummaryMedium Risk Overview Query engine: New ClickHouse translation ranks points per group (hidden Subqueries: Fixes aggregate/subquery Compat and two-region integration tests cover selectors, subqueries, and multi-region behavior. Reviewed by Cursor Bugbot for commit 3637d91. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 3637d91. Configure here.
| .await?; | ||
| return Ok(crate::domain::sharding::multi_selector::rerank( | ||
| &sel, &named, series, | ||
| )); |
There was a problem hiding this comment.
LIMIT applied twice on local fallback
Medium Severity
When shard_routing is set, top/bottom/sample always rerank, which applies LIMIT/OFFSET again. Region SQL strips those clauses first, but the no-space path still runs the original statement locally, so LIMIT/OFFSET is already in the SQL. A query such as top(v, 3) LIMIT 1 OFFSET 1 can return too few points or none on a sharded node that falls back to a local table.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3637d91. Configure here.
There was a problem hiding this comment.
Right, thanks. Fixed in e533adf: the sharded path now gets the statement without LIMIT/OFFSET on every route (regions and the local fallback), and only the re-rank applies them. Test: top_limit_offset_on_the_local_fallback_applies_once (drops the shard space so the node falls back to its table); it returns no points with the old code.
There was a problem hiding this comment.
Stale comment
Left a non-blocking comment: Cursor Bugbot reported one unresolved medium-severity issue on this head (LIMIT/OFFSET can be applied twice on the local fallback path), so I am not approving. Human review is needed, and no reviewers were assigned.
Sent by Cursor Approval Agent: Pull Request Router and Approver
…llback A measurement with no shard space is queried from the node's own table, with the statement as given: its SQL applied LIMIT and OFFSET, then the coordinator's re-rank applied them again, so `top(v, 3) LIMIT 1 OFFSET 1` returned nothing. The sharded path now gets the statement without them, on every route; only the re-rank applies them.




top(),bottom()andsample()work. They were rejected with "unsupported aggregate function".topandbottombreak ties by the earliest point.top/bottomtake tag arguments (at most one point per combination). Other fields or tags can be selected beside them, taken from the same points.SELECT * FROM (\n...\n)layout, so region and tombstone predicates still filter the points before ranking.timeinside its own SQL, so ClickHouse readtimein its GROUP BY as the bucket (NOT_AN_AGGREGATE). An inner aggregate without buckets had notimecolumn at all.time: the bucket, a lone selector's point time, or the query's lower bound (as InfluxDB does).__time(a string, or the client's epoch unit), so every outer query on time failed. They now carry a realtimecolumn.Tests:
Compat suite (real chDB): values checked by hand against the data. The suite covers top with and without tags, extra fields, bottom per bucket and host, sample counts, the error cases, subqueries over buckets, over unbucketed aggregates, and over and under
top.Two-region sharded tests:
With the coordinator re-rank removed, the sharded test fails, returning each region's own top 2.
Unit tests for the re-rank.
CI-equivalent run (libchdb 26.9.0,
-D warnings): passes.Docs: the selector functions are added to the reference; the clustering deep-dive lists how they merge across regions.