Trait udf::AggregateUdf

source ·
pub trait AggregateUdf: BasicUdf {
    // Required methods
    fn clear(
        &mut self,
        cfg: &UdfCfg<Process>,
        error: Option<NonZeroU8>
    ) -> Result<(), NonZeroU8>;
    fn add(
        &mut self,
        cfg: &UdfCfg<Process>,
        args: &ArgList<'_, Process>,
        error: Option<NonZeroU8>
    ) -> Result<(), NonZeroU8>;

    // Provided method
    fn remove(
        &mut self,
        cfg: &UdfCfg<Process>,
        args: &ArgList<'_, Process>,
        error: Option<NonZeroU8>
    ) -> Result<(), NonZeroU8> { ... }
}
Expand description

This trait must be implemented if this function performs aggregation.

The basics of aggregation are simple:

  • init is called once per result set (same as non-aggregate)
  • clear is called once per group within the result set, and should reset your struct
  • add is called once per row in the group, and should add the current row to the struct as needed
  • process is called at the end of each group, and should produce the result value for that group

Aggregate Error Handling

Error handling for aggregate functions is weird, and does not lend itself to easy understandability. The following is my best understanding of the process:

  • Any aggregate function may set a nonzero error (Represented here in return value by Err(NonZeroU8)). The value is not important, can be something internal
  • These errors do not stop the remaining add()/remove() functions from being called, but these functions do receive the error (and so may choose to do nothing if there is an error set)
  • Errors are not reset on clear(); you must do this manually (Hence error being mutable in this function signature)

In order to enforce some of these constraints, we use NonZeroU8 to represent error types (which has the nice side effect of being optimizable). Unfortunately, it is somewhat cumbersome to use, e.g.: return Err(NonZeroU8::new(1).unwrap());

Required Methods§

source

fn clear( &mut self, cfg: &UdfCfg<Process>, error: Option<NonZeroU8> ) -> Result<(), NonZeroU8>

Clear is run once at the beginning of each aggregate group and should reset everything needed in the struct.

Errors

The error arg provides the error value from the previous group, and this function may choose to reset it (that is probably a good idea to do). error will be None if there is currently no error.

To clear the error, simply return Ok(()).

Return an error if something goes wrong within this function, or if you would like to propegate the previous error.

source

fn add( &mut self, cfg: &UdfCfg<Process>, args: &ArgList<'_, Process>, error: Option<NonZeroU8> ) -> Result<(), NonZeroU8>

Add an item to the aggregate

Usually this is implemented by adding something to an intemdiate value inside the core struct type.

Errors

Hit a problem? Return an integer, which may or may not be meaningful to you. This can be done with return Err(NonZeroU8::new(1).unwrap());.

The error argument tells you if there has been an error at some point, and the return value also detemines whether to propegate/modify the error (probably what you want) or clear it (I can’t think of any good reason to do this in add()). If you would like to propegate the error without action, just add the following as the first line of the function:

error.map_or(Ok(()), Err)?;

If you do this,

Provided Methods§

source

fn remove( &mut self, cfg: &UdfCfg<Process>, args: &ArgList<'_, Process>, error: Option<NonZeroU8> ) -> Result<(), NonZeroU8>

Remove only applies to MariaDB, for use with window functions; i.e., remove will be called on a row that should be removed from the current set (has moved out of the window).

This is optional; a default is supplied so no action is needed. If you would like to use remove, just reimplement it.

https://mariadb.com/kb/en/user-defined-functions-calling-sequences/#x_remove

Errors

Errors are handled the same as with AggregateUdf::add(), see the description there

Implementors§