Skip to content

feat(bindings): aggregate function infrastructure — extent(span) for all 5 span types#47

Merged
nhungoc1508 merged 1 commit into
mainfrom
feat/aggregate-fn-extent
Apr 30, 2026
Merged

feat(bindings): aggregate function infrastructure — extent(span) for all 5 span types#47
nhungoc1508 merged 1 commit into
mainfrom
feat/aggregate-fn-extent

Conversation

@estebanzimanyi

Copy link
Copy Markdown
Member

Summary

Lands the first MobilityDuck AggregateFunction registration. Adds `extent(span)` that aggregates a column of spans into the bounding span over all values, for the 5 span types: `intspan`, `bigintspan`, `floatspan`, `datespan`, `tstzspan`.

```sql
SELECT extent(s) FROM (VALUES (intspan '[1, 5)'), (intspan '[3, 8)'), (intspan '[10, 12)')) t(s);
-- [1, 12)

SELECT extent(s) FROM (VALUES (datespan '[2000-01-01, 2000-01-05]'), (datespan '[2000-01-03, 2000-01-10]')) t(s);
-- [2000-01-01, 2000-01-11)
```

Implementation pattern

New module: `src/temporal/span_aggregates.cpp` + `src/include/temporal/span_aggregates.hpp`.

Component What it does
`SpanExtentState` Inline `Span span` + `bool isset`. MEOS Span is POD/fixed-size — state is trivially serialisable.
`SpanExtentFunction::Initialize` Sets `isset = false`.
`SpanExtentFunction::Operation` Decodes the input blob, calls MEOS `span_extent_transfn` to expand state in place.
`SpanExtentFunction::Combine` Calls `span_extent_transfn(&target.span, &source.span)`.
`SpanExtentFunction::Finalize` Returns `finalize_data.ReturnString(string_t(&state.span, sizeof(Span)))` or NULL when no input was seen.
Registration One `AggregateFunctionSet("extent")` with 5 type-overloads (one per span type). Bundled because separate `AggregateFunction` registrations triggered DuckDB's catalog-alter path which doesn't implement `GetAlterInfo` for `CreateAggregateFunctionInfo`.

The same scaffolding extends naturally to the rest of the aggregate surface (architectural blocker for parity tests #21, #40, parts of #25):

  • `extent(spanset)` via `spanset_extent_transfn`
  • `extent(set)` via `set_extent_transfn`
  • `extent(tnumber) → tbox` via `tnumber_extent_transfn`
  • `tcount` / `tand` / `tor` / `tmin` / `tmax` / `tsum` via skiplist-backed states (more state setup)
  • `spanUnion(span) → spanset` via `spanset_union_transfn`

This PR establishes the bridging pattern; follow-up PRs land each of the above on the same scaffolding.

Test plan

  • Smoke test all 5 span types — produces correct extent
  • NULL handling: mixed NULL + value → returns the value's extent; all-NULL → returns NULL
  • Multi-row aggregation produces correct expanding bounds
  • Existing test suite still passes locally

…n types

Lands the first MobilityDuck AggregateFunction registration: extent(span)
that aggregates a column of spans into the bounding span of all values.
Registers a single AggregateFunctionSet "extent" with five overloads
(intspan, bigintspan, floatspan, datespan, tstzspan).

Implementation pattern (in src/temporal/span_aggregates.cpp):

- SpanExtentState holds an inline Span + bool isset. The MEOS Span is
  a fixed-size struct so the state is POD and trivially serialisable.
- SpanExtentFunction provides Initialize / Operation / ConstantOperation
  / Combine / Finalize via DuckDB's UnaryAggregate template helper.
- Operation and Combine bridge to MEOS span_extent_transfn, which
  expands state's bounds in place when state is non-null and otherwise
  returns a fresh palloc'd copy. Since our state is inline we just
  memcpy the Span on first input.
- Finalize uses finalize_data.ReturnString(string_t(&state.span,
  sizeof(Span))) to emit the result blob.

This pattern extends naturally to:
  - extent(spanset)  via spanset_extent_transfn
  - extent(set)      via set_extent_transfn
  - extent(tnumber)  via tnumber_extent_transfn (returns TBox state)
  - tcount / tand / tor / tmin / tmax / tsum  via skiplist-backed states
  - spanUnion(span)  via spanset_union_transfn

This first PR establishes the infrastructure; follow-up PRs land each
of the listed aggregates against the same scaffolding.
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.

2 participants