Hello everyone,
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
In udf/examples
, basic_sum
and 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
char*
,long long
, ordouble
. 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 aroundUDF_ARGS
-
SqlArg<S>
a single SQL argument that has a value (SqlResult
type) and an attribute (its name).S
is a ZST, eitherInit
orProcess
, which allows for some additional methods to be used that are only relevant during the init step. -
SqlResult
lines up with a SQL type (string/bytes[u8]
, integeri54
, realf64
, or decimal also[u8]
) -
InitCfg
, a wrapper aroundUDF_INIT
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.