You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0af2a50
Browse filesBrowse the repository at this point in the historyBrowse files
feat: let extension bundles declare scalar, aggregate, and window functions
`SessionExtensionComponents` gains `udfs`, `udafs`, and `udwfs`, so a library
shipping functions can be installed with one `with_extensions` call instead of
documenting a per-function `register_*` recipe. Either the Python wrapper or a
raw capsule exportable is accepted; the registered name comes off the function.
Installation now splits into a fallible part and an infallible one. Collecting
hooks, building the codec chains, resolving the declared functions, and running
the planner hooks all write nothing; only the final step binds the planner and
registers. That keeps "nothing is written until every hook has returned" true
now that components reach the shared `SessionState`, where there is nothing to
roll back to. A new comment states the rule for whoever adds the next field.
Two extensions declaring one name in a single call is a `ValueError` naming
both, since a function registry has no fall-through the way a codec chain does.
Shadowing a name the session already has stays legal, which
`enable_spark_functions` relies on.
`__post_init__` now normalizes fields by metadata rather than by the `_codecs`
name suffix, so the new fields are covered and later ones will be too.
`MyFunctionExtension` in `datafusion-ffi-example` declares this crate's three
functions across a real FFI boundary.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: examples/datafusion-ffi-example/README.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,6 +29,10 @@ The example intentionally uses separate `cdylib` crates for these roles:
29
29
30
30
Separate shared libraries guarantee distinct DataFusion library markers. This catches type-identity mistakes that a planner and provider compiled into one shared library would hide.
31
31
32
+
## Installing the functions as a bundle
33
+
34
+
`MyFunctionExtension` implements `__datafusion_session_components__` and declares this crate's scalar, aggregate, and window functions, so a caller installs all three with one `SessionContext.with_extensions(MyFunctionExtension())` rather than wrapping and registering each in turn. It contributes no codecs and no planner, which is the shape a function-only library takes. `python/tests/_test_session_extension.py` covers it, including that a failure after the hook registers nothing.
35
+
32
36
## Codec behavior
33
37
34
38
`MyLogicalExtensionCodec` serializes this example's in-memory table providers, and `MyPhysicalExtensionCodec` serializes provider-owned memory scans and opaque FFI wrappers around them. Both use documented, process-local, one-shot token registries. The registries make ownership and callback routing visible without pretending to be a portable format. They assume trusted in-process payloads and consume each token during decoding. A production provider should instead encode durable metadata from which its provider and plans can be reconstructed.
0 commit comments