Skip to content

feat: add cross-shard HAVING support for grouped aggregates - #1841

Open
murex971 wants to merge 19 commits into
mainfrom
murex-having-support
Open

murex971 wants to merge 19 commits into
mainfrom
murex-having-support

Conversation

@murex971

@murex971 murex971 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

closes #695

@murex971 murex971 changed the title feat: add support for Having clause feat: add cross-shard HAVING support for grouped aggregates Oct 16, 2026
@codecov

codecov Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

ProjectPgDog
Branchmurex-having-support
TestbedIntel v1
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s) x 1e3
(Result Δ%)
Lower Boundary
operations / second (ops/s) x 1e3
(Limit %)
cpu-per-txnBenchmark Result
Measure (units)
(Result Δ%)
Upper Boundary
Measure (units)
(Limit %)
lb-v3📈 view plot
🚷 view threshold
15.99 ops/s x 1e3
(+0.00%)Baseline: 15.99 ops/s x 1e3
15.83 ops/s x 1e3
(99.00%)
📈 view plot
🚷 view threshold
42.02 units
(+0.97%)Baseline: 41.62 units
42.03 units
(99.97%)
🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

ProjectPgDog
Branchmurex-having-support
TestbedIntel v1

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

ProjectPgDog
Branchmurex-having-support
TestbedIntel v1

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
pooler-v3cpu-per-txn
Measure (units)
📈 plot
🚷 threshold
🚨 alert (🔔)
40.95 units
(+1.50%)Baseline: 40.35 units
40.75 units
(100.49%)

Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s) x 1e3
(Result Δ%)
Lower Boundary
operations / second (ops/s) x 1e3
(Limit %)
cpu-per-txnBenchmark Result
Measure (units)
(Result Δ%)
Upper Boundary
Measure (units)
(Limit %)
pooler-v3📈 view plot
🚷 view threshold
16.99 ops/s x 1e3
(-0.00%)Baseline: 16.99 ops/s x 1e3
16.82 ops/s x 1e3
(99.00%)
📈 view plot
🚷 view threshold
🚨 view alert (🔔)
40.95 units
(+1.50%)Baseline: 40.35 units
40.75 units
(100.49%)

🐰 View full continuous benchmarking report in Bencher

@jkaczman

Copy link
Copy Markdown
Contributor

Working on adjusting Bencher, please ignore those alerts for now

@jkaczman
jkaczman force-pushed the murex-having-support branch from 0242c2a to d39bcef Compare October 16, 2026 16:48
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/projection.rs Outdated
@jkaczman
jkaczman self-requested a review October 17, 2026 00:02
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/having.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/projection.rs
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/projection.rs
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/projection.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/having.rs
Comment thread pgdog/src/backend/pool/connection/buffer/having.rs Outdated
Comment thread pgdog/src/backend/pool/connection/multi_shard/mod.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/having.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/having.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/having.rs Outdated

@jkaczman jkaczman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also recommend adding HAVING to

})
.await
.unwrap_or_else(|_| panic!("unsupported aggregation or subsequent query hung: {begin:?}"));
}
}

(in ref. to #1802 (fix for #1795)), this code seems to add a case where it could propagate UnsupportedHaving off of

projection::finalize_after_route(
client_request,
&cluster.schema(),
rewrite_result.and_then(RewriteResult::offset_plan),
)?;
if let Some(rewrite_result) = rewrite_result {
rewrite_result.apply_after_route(client_request)?;

and disconnect the client

Comment thread pgdog/src/backend/pool/connection/buffer/having.rs Outdated
Comment thread pgdog/src/backend/pool/connection/buffer/having.rs Outdated
Comment thread integration/rust/tests/integration/having.rs
Comment thread integration/rust/tests/integration/having.rs Outdated
Comment thread pgdog/src/backend/pool/connection/buffer.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/projection.rs Outdated
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/projection.rs
Comment thread pgdog/src/frontend/router/parser/rewrite/statement/having.rs Outdated
@murex971

Copy link
Copy Markdown
Contributor Author

@jkaczman addressed

@jkaczman
jkaczman force-pushed the murex-having-support branch from eaf189d to b0566fb Compare October 21, 2026 13:45
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

ProjectPgDog
Branchmurex-having-support
TestbedIntel v1
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s) x 1e3
(Result Δ%)
Lower Boundary
operations / second (ops/s) x 1e3
(Limit %)
cpu-per-txnBenchmark Result
Measure (units)
(Result Δ%)
Upper Boundary
Measure (units)
(Limit %)
ctx-switches-per-txnBenchmark Result
Measure (units)
(Result Δ%)
Upper Boundary
Measure (units)
(Limit %)
sharding-w2-v3📈 view plot
🚷 view threshold
10.00 ops/s x 1e3
(+0.00%)Baseline: 10.00 ops/s x 1e3
9.90 ops/s x 1e3
(99.00%)
📈 view plot
🚷 view threshold
62.59 units
(-0.07%)Baseline: 62.63 units
63.26 units
(98.94%)
📈 view plot
🚷 view threshold
1.27 units
(+0.71%)Baseline: 1.26 units
1.30 units
(97.77%)
🐰 View full continuous benchmarking report in Bencher

@jkaczman
jkaczman force-pushed the murex-having-support branch 2 times, most recently from 4ca2dcc to 7f92f25 Compare October 22, 2026 21:25
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench failed. 3 of 150 measures outside bounds.

suite throughput cpu/txn user cycles/txn user instr/txn kernel cycles/txn ctx/txn
pooler 27.78 (-1.5% ± 0.8%) 27,006 (-1.9% ± 1.0%) 35,060 (+0.0% ± 0.02%) 38,726 (-0.8% ± 1.3%)
lb 28.8 (-1.3% ± 1.0%) 28,436 (-1.4% ± 1.4%) 35,919 (+0.0% ± 0.02%) 39,750 (-0.8% ± 1.4%)
sharding-w2 52.49 (+3.1%), bound +3% 65,970 (+3.1%), bound +3% 72,282 (+0.0%) 61,054 (+3.3%) 1.419 (-0.6%)
sharding-w8 156,928 (-2.4%) 46.46 (+2.7%) 66,663 (+3.8%), bound +3% 56,105 (+0.0%) 53,008 (+1.6%) 0.1495 (-2.1%)
  • sharding-w2: user cycles +3.1%, instructions flat. Unexplained.
  • sharding-w8: user cycles +3.8%, instructions flat. Unexplained.
Counters per txn
suite frontend stall l1i refill backend stall
pooler 13,026 (-3.6% ± 1.9%) 3,103 (-1.0% ± 0.7%) 2,635 (-0.1% ± 2.2%)
lb 13,861 (-2.7% ± 2.9%) 3,185 (-0.8% ± 1.2%) 2,918 (+0.9% ± 2.2%)
sharding-w2 37,174 (+6.0%) 5,243 (+1.6%) 7,133 (-1.6%)
sharding-w8 37,663 (+8.9%) 4,972 (+2.5%) 9,466 (-6.6%)

Microbench: all 135 measures within bounds.

lb flamegraph vs 692b9d9

lb

Open interactive for hover, zoom and search.

lb removed

Open interactive.

microbench flamegraph vs 692b9d9

microbench

Open interactive for hover, zoom and search.

microbench removed

Open interactive.

pooler flamegraph vs 692b9d9

pooler

Open interactive for hover, zoom and search.

pooler removed

Open interactive.

sharding-w2 flamegraph vs 692b9d9

sharding-w2

Open interactive for hover, zoom and search.

sharding-w2 removed

Open interactive.

sharding-w8 flamegraph vs 692b9d9

sharding-w8

Open interactive for hover, zoom and search.

sharding-w8 removed

Open interactive.

Logs

lb, microbench, pooler, sharding-w2, sharding-w8, verdict.json

Compared d9348d5 with 692b9d9.

@jkaczman

Copy link
Copy Markdown
Contributor

What are your thoughts on splitting this into multiple stacked PRs? I think it'd help address some of the things I mentioned above as well as make it less likely for us to miss something.

@murex971

Copy link
Copy Markdown
Contributor Author

What are your thoughts on splitting this into multiple stacked PRs? I think it'd help address some of the things I mentioned above as well as make it less likely for us to miss something.

I am not sure if we can split the having feature itself into multiple PRs, but I can definitely separate out some refactoring that was done in this PR around ProjectRewrite

@murex971
murex971 changed the base branch from main to project-rewrite-refactor October 27, 2026 08:47
@murex971
murex971 added this pull request to stack #1903 October 27, 2026 08:57
@jkaczman

Copy link
Copy Markdown
Contributor

Hmm.. how about this? Ideally each of these is less than 500 LOC.

  1. refactor: shared projection rewrite plan as Option #1902
  2. Reject cross-shard HAVING with an explicit error
  3. Main infra: support one condition per HAVING, e.g., HAVING count(*) > 3 or HAVING count(*) > $1
  4. Extends on 3 by handling AND/OR/NOT and NULLs, e.g., HAVING count(*) > 3 AND max(shipped_at) IS NULL
  5. Extends on 4 by handling decimals and floats, e.g., HAVING sum(price) > 99.99 or HAVING count(*)::numeric > 3

@murex971
murex971 removed this pull request from stack #1903 October 27, 2026 15:50
@murex971
murex971 changed the base branch from project-rewrite-refactor to having-reject October 27, 2026 15:51
@murex971
murex971 added this pull request to stack #1907 October 27, 2026 15:52
Base automatically changed from having-reject to main October 27, 2026 19:26

@jkaczman jkaczman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest splitting this up again due to it being over >1000 LOC, perhaps like this, although feel free to devise your own split if you have a better idea!

Execution (first)

  • apply HAVING after merging shards' results
  • don't wire in yet, continue to error from the prev stacked PR (re #1906)
  • code:
    • parser/having.rs
    • buffer/having.rs
    • Buffer::having() in buffer.rs
    • AggregateError variants in aggregate/error.rs
    • is_unsupported() in backend/error.rs
    • ProjectionRewritePlan.having in projection.rs
  • explicit unit tests to exercise all functionality via hand-built HAVING plan (extended upon with integration tests in planning)

Planning (second)

  • rewrite the query sent to the shards
  • wire in Buffer::having(), remove error from prev stacked PR
  • code:
    • rewrite/statement/having.rs
    • build() and finalize_after_route() in projection.rs
    • Buffer::having() call in multi_shard/mod.rs
    • Route::set_aggregate() in route.rs
    • AggregateFunction::from_builtin_name() in parser/aggregate.rs
  • rewriter, query engine and integration tests

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Query engine] Support HAVING in aggregates

2 participants