I am hoping for a review of
udf, which is a crate aiming to make it easy to write UDFs (user-defined functions) for MariaDB and MySQL Quick relevant links:
- Source code: GitHub - pluots/sql-udf: A wrapper for MariaDB/MySQL user defined functions in Rust
- Current docs (text is very unfinished): udf - Rust
- MariaDB UDF reference: User-Defined Functions Calling Sequences - MariaDB Knowledge Base
- MySQL UDF reference: MySQL :: Extending MySQL 8.0 :: 6.2 Adding a Loadable Function
- Original C types & headers are in the repo, along with a C++ example of various UDFs sql-udf/reference at main · pluots/sql-udf · GitHub
sequence are my two working examples - please disregard the others for now.
UDFs are just dynamic libraries that provide three functions:
- An init function, takes a config struct and a list of arguments. Validates arguments or sets type coercion, sets max arg length (for caller's optimization), allocates if needed. Arguments may or may not be present at this time, depending on if they are constant.
- A process function that takes arguments (these will always be present) and returns data of a fixed type - either
long long, or
double. If returning a string (
char*) over a fixed length, it must be allocated in the first step (which is why I had to use GATs here, as I'll cover later)
- "Aggregate" UDFs have two more functions, but they are fairly trivial
- A deinit function - I don't need to expose this one since Rust handles it
To represent this, I have chosen to provide two traits - one for basic UDFs
BasicUdf that is required, and a
AggregateUdf for aggregate UDFs. The user can implement any of these on a struct and use my macro
#[register] on the
impl blocks. The
Returns type within the trait specifies whether the function will be a string, integer, or float. If it is a long string, it needs to return a reference to a field in the implemented struct (hence GATs).
Relevant types (from my library) are:
ArgList<S>, a collection of SQL arguments, this is a wrapper around
SqlArg<S>a single SQL argument that has a value (
SqlResulttype) and an attribute (its name).
Sis a ZST, either
Process, which allows for some additional methods to be used that are only relevant during the init step.
SqlResultlines up with a SQL type (string/bytes
f64, or decimal also
InitCfg, a wrapper around
I think I am planning to change
InitCfg to use some interior mutability (like I do for
SqlArg) to clean up the
init function signature, since mutability of
cfg isn't needed in most use cases.
I am mostly looking for feedback on the function signatures within the traits, and organization of public types, since that will be the most set in stone.
Thank you anyone who is able to take a look! I am happy to answer any follow up questions.