Skip to content

Call AggregateSeqFunction for empty input groups#390

Merged
ncruces merged 1 commit into
ncruces:mainfrom
SAY-5:fix-aggregate-empty-input
May 20, 2026
Merged

Call AggregateSeqFunction for empty input groups#390
ncruces merged 1 commit into
ncruces:mainfrom
SAY-5:fix-aggregate-empty-input

Conversation

@SAY-5

@SAY-5 SAY-5 commented May 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #389.

CreateAggregateFunction never invokes the user's AggregateSeqFunction when a group has zero input rows, because the iter.Pull coroutine only runs the callback after the first Step. SQLite's xFinal contract calls for exactly one invocation per group, so an ungrouped custom aggregate over an empty input returns NULL instead of the documented value (e.g. 0 for a count).

Track whether Step ran on the aggregateFunc, and if not, invoke the user callback directly from Value with an empty seq. The coroutine path is unchanged for the common case.

Verified with the issue's repro:

builtin count(*)     -> 0
custom my_count()    -> 0   (was: NULL)

Added TestAggregateSeqFunction_EmptyInput which fails on main and passes with the fix. Existing go test -race ./... is green on . and ./tests/....

The per-group callback registered via CreateAggregateFunction was
never invoked when a group had zero input rows, because the
iter.Pull-backed coroutine only runs the user callback after the
first Step. SQLite's xFinal contract calls for exactly one
invocation per group, including the implicit single-group case
of an ungrouped aggregate over an empty input.

Track whether Step ran and, if not, invoke the user callback
directly with an empty seq from Value. Fixes ncruces#389.
@ncruces ncruces changed the title fix: invoke AggregateSeqFunction xFinal for empty input groups Call AggregateSeqFunction for empty input groups May 20, 2026
@ncruces ncruces merged commit 7914383 into ncruces:main May 20, 2026
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.

CreateAggregateFunction skips the per-group callback for empty groups, diverging from SQLite's documented xFinal semantics

2 participants