-
-
Notifications
You must be signed in to change notification settings - Fork 727
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for custom aggregate functions #236
Comments
Hello @hashemi, Thanks for your feature request, and your analysis! For the record, the SQLite reference about custom aggregate functions is here: https://sqlite.org/c3ref/create_function.html Do you wish somebody takes care of adding support for custom aggregate functions, or do you feel like submitting a pull request? |
I'e been fiddling a little bit, this requires a heavy load of Swift pointer/retain/release wizardry 😅 ! |
Superseded by #237 |
GRDB currently supports defining custom SQL functions. However, it doesn't support custom aggregate functions. I looked into it and here are my notes.
In the C interface, a custom SQLite aggregate function is defined as a pair of functions:
step
andfinal
. Step is called for each row and does not return a value but instead keeps track of the data somehow. Final is called at the end and returns the actual result of the aggregate.For example, in an
average
aggregate function, whenstep
is called and is passed a value from a row, it adds the value to a sum and increments a count variable. Whenfinal
is called, it divides the sum by the count and returns an average as an SQL value.In PHP, the user implements a couple of functions for step and finalize. The first argument the functions is passed by reference with each call and is used to keep track of state between calls to
step
and the last call tofinal
:In Python, it's done by writing a class that has
step
andfinalize
.step
takes a single argument (database value) and does not return.finalize
does not take any arguments and returns the final result. State is tracked in instance variables of the class:I think we could use a technique similar to either in Swift:
context
of a generic type as aninout
. The step function is called with thiscontext
as well as a database value per row. Thefinal
function is called with thecontext
only and is expected to return a database value. The GRDB API would expect an instance of this struct (or class) type.Here's an example of what the interface looks like:
step
function that takes a singe database value and afinal
function that takes no arguments and returns a final value. The aggregate would be passed to the GRDB API as a type that is instantiated every time the aggregate function is called within SQLite.This is an example of what the code would look like:
The current implementation of custom functions uses the first method, except that there isn't the added complexity of this
inout context
variable to track state and there's only one function required which works well with Swift's trailing closure syntax.I'd really appreciate your thoughts on this and whether this is something that would be considered for GRDB. The Swift/C interface is currently outside of my comfort level so I don't think I'd be able to implement it myself although I'm willing to give it a try if it's desirable. I do need the functionality for a project I'm working on now but may end up using a workaround.
The text was updated successfully, but these errors were encountered: