The "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 sub-aggregate values and produce the super-aggregate result.
#include "extfnapiv3.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 UDAF, 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