The aggregate UDF my_bit_xor example is similar to the SA built-in BIT_XOR, except my_bit_xor operates only on unsigned integers.
Because the input and the output data types are identical, use the normal _next_value_extfn and _evaluate_extfn functions to accumulate subaggregate values and produce the superaggregate result.
#include "extfnapiv4.h"
#include <stdlib.h>
#include <assert.h>
// Generic aggregate UDF that exclusive-ORs a set of
// unsigned integer arguments, and whenever asked
// returns the resulting unsigned integer result.
//
// The start function creates a little structure for
// the running result, and the finish function then
// deallocates it.
//
// Since there are no aggregate usage restrictions
// for this aggregate UDF, the corresponding SQL declaration
// will look like:
//
// CREATE AGGREGATE FUNCTION my_bit_xor(IN arg1 UNSIGNED INT)
// RETURNS UNSIGNED INT
// ON EMPTY INPUT RETURNS NULL
// EXTERNAL NAME 'my_bit_xor@libudfex'
typedef struct my_xor_result {
a_sql_uint64 _num_nonnulls_seen;
a_sql_uint32 _xor_result;
} my_xor_result;
#if defined __cplusplus
extern "C" {
#endif
static void my_xor_start(a_v3_extfn_aggregate_context *cntxt)
{
}
static void my_xor_finish(a_v3_extfn_aggregate_context *cntxt)
{
}
static void my_xor_reset(a_v3_extfn_aggregate_context *cntxt)
{
my_xor_result *cptr = (my_xor_result *)cntxt->_user_calculation_context;
cptr->_xor_result = 0;
cptr->_num_nonnulls_seen = 0;
}
static void my_xor_next_value(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value arg;
a_sql_uint32 arg1;
my_xor_result *cptr = (my_xor_result *)cntxt->_user_calculation_context;
// Get the one argument, and add it to the total
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_uint32 *)arg.data);
cptr->_xor_result ^= arg1;
cptr->_num_nonnulls_seen++;
}
}
static void my_xor_drop_value(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value arg;
a_sql_uint32 arg1;
my_xor_result *cptr = (my_xor_result *)cntxt->_user_calculation_context;
// Get the one argument, and remove it from the total
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_uint32 *)arg.data);
cptr->_xor_result ^= arg1;
cptr->_num_nonnulls_seen--;
}
}
static void my_xor_evaluate(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value outval;
my_xor_result *cptr = (my_xor_result *)cntxt->_user_calculation_context;
outval.type = DT_UNSINT;
outval.piece_len = sizeof(a_sql_uint32);
if (cptr->_num_nonnulls_seen > 0) {
outval.data = &cptr->_xor_result;
} else {
outval.data = 0;
}
cntxt->set_value( arg_handle, &outval, 0 );
}
static void my_xor_cum_evaluate(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value outval;
an_extfn_value arg;
a_sql_uint32 arg1;
my_xor_result *cptr = (my_xor_result *)cntxt->_user_calculation_context;
// Get the one argument, and include it in the result,
// unless that input value is null.
//
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_uint32 *)arg.data);
cptr->_xor_result ^= arg1;
cptr->_num_nonnulls_seen++;
}
// Then set the output result value
outval.type = DT_UNSINT;
outval.piece_len = sizeof(a_sql_uint32);
if (cptr->_num_nonnulls_seen > 0) {
outval.data = &cptr->_xor_result;
} else {
outval.data = 0;
}
cntxt->set_value( arg_handle, &outval, 0 );
}
static a_v3_extfn_aggregate my_xor_descriptor =
{
&my_xor_start,
&my_xor_finish,
&my_xor_reset,
&my_xor_next_value,
&my_xor_evaluate,
&my_xor_drop_value,
&my_xor_cum_evaluate,
&my_xor_next_value,
&my_xor_drop_value,
&my_xor_evaluate,
NULL, // reserved1_must_be_null
NULL, // reserved2_must_be_null
NULL, // reserved3_must_be_null
NULL, // reserved4_must_be_null
NULL, // reserved5_must_be_null
0, // indicators
( short )sizeof( my_xor_result ), // context size
8, // context alignment
0.0, // external_bytes_per_group
0.0, // external bytes per row
0, // reserved6_must_be_null
0, // reserved7_must_be_null
0, // reserved8_must_be_null
0, // reserved9_must_be_null
0, // reserved10_must_be_null
NULL // _for_server_internal_use
};
a_v3_extfn_aggregate *my_bit_xor()
{
return &my_xor_descriptor;
}
#if defined __cplusplus
}
#endif