The "my_sum" example operates only on integers.
Since my_sum, like SUM, can be used in any context, all the optimized optional entry points have been supplied. In this example, the normal _evaluate_extfn function can also be used as the _evaluate_superaggregate_extfn function.
#include "extfnapiv3.h" #include <stdlib.h> #include <assert.h> // Simple aggregate UDF that adds up a set of // integer arguments, and whenever asked returns // the resulting big integer total. For int // arguments, the only difference between this // UDF and the SUM built-in aggregate is that this // UDF will return NULL if there are no input rows. // // The start function creates a little structure for // the running total, 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_sum(IN arg1 INT) // RETURNS BIGINT // ON EMPTY INPUT RETURNS NULL // EXTERNAL NAME 'my_integer_sum@libudfex' typedef struct my_total { a_sql_int64 _total; a_sql_uint64 _num_nonnulls_seen; } my_total; extern "C" void my_integer_sum_start(a_v3_extfn_aggregate_context *cntxt) { } extern "C" void my_integer_sum_finish(a_v3_extfn_aggregate_context *cntxt) { } extern "C" void my_integer_sum_reset(a_v3_extfn_aggregate_context *cntxt) { my_total *cptr = (my_total *)cntxt->_user_calculation_context; cptr->_total = 0; cptr->_num_nonnulls_seen = 0; } extern "C" void my_integer_sum_next_value(a_v3_extfn_aggregate_context *cntxt, void *arg_handle) { an_extfn_value arg; a_sql_int32 arg1; my_total *cptr = (my_total *)cntxt->_user_calculation_context; // Get the one argument, and if non-NULL then add it to the total // if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) { arg1 = *((a_sql_int32 *)arg.data); cptr->_total += arg1; cptr->_num_nonnulls_seen++; } } extern "C" void my_integer_sum_drop_value(a_v3_extfn_aggregate_context *cntxt, void *arg_handle) { an_extfn_value arg; a_sql_int32 arg1; my_total *cptr = (my_total *)cntxt->_user_calculation_context; // Get the one argument, and if non-NULL then subtract it from the total if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) { arg1 = *((a_sql_int32 *)arg.data); cptr->_total -= arg1; cptr->_num_nonnulls_seen--; } } extern "C" void my_integer_sum_evaluate(a_v3_extfn_aggregate_context *cntxt, void *arg_handle) { an_extfn_value outval; my_total *cptr = (my_total *)cntxt->_user_calculation_context; // Set the output result value. If the inputs // were all NULL, then set the result as NULL. // outval.type = DT_BIGINT; outval.piece_len = sizeof(a_sql_int64); if (cptr->_num_nonnulls_seen > 0) { outval.data = &cptr->_total; } else { outval.data = 0; } cntxt->set_value( arg_handle, &outval, 0 ); } extern "C" void my_integer_sum_cum_evaluate( a_v3_extfn_aggregate_context *cntxt, void *arg_handle) { an_extfn_value outval; an_extfn_value arg; int arg1; my_total *cptr = (my_total *)cntxt->_user_calculation_context; // Get the one argument, and if non-NULL then add it into the total. // if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) { arg1 = *((a_sql_int32 *)arg.data); cptr->_total += arg1; cptr->_num_nonnulls_seen++; } // Then set the output result value. If the inputs // were all NULL, then set the result as NULL. // outval.type = DT_BIGINT; outval.piece_len = sizeof(a_sql_int64); if (cptr->_num_nonnulls_seen > 0) { outval.data = &cptr->_total; } else { outval.data = 0; } cntxt->set_value( arg_handle, &outval, 0 ); } extern "C" void my_integer_sum_next_subagg_value( a_v3_extfn_aggregate_context *cntxt, void *arg_handle) { an_extfn_value arg; a_sql_int64 arg1; my_total *cptr = (my_total *)cntxt->_user_calculation_context; // Get the one argument, and if non-NULL then add it to the total // if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) { arg1 = *((a_sql_int64 *)arg.data); cptr->_total += arg1; cptr->_num_nonnulls_seen++; } } extern "C" void my_integer_sum_drop_subagg_value( a_v3_extfn_aggregate_context *cntxt, void *arg_handle) { an_extfn_value arg; a_sql_int64 arg1; my_total *cptr = (my_total *)cntxt->_user_calculation_context; // Get the one argument, and if non-NULL then subtract it from the total // if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) { arg1 = *((a_sql_int64 *)arg.data); cptr->_total -= arg1; cptr->_num_nonnulls_seen--; } } a_v3_extfn_aggregate my_integer_sum_descriptor = { &my_integer_sum_start, &my_integer_sum_finish, &my_integer_sum_reset, &my_integer_sum_next_value, &my_integer_sum_evaluate, &my_integer_sum_drop_value, &my_integer_sum_cum_evaluate, &my_integer_sum_next_subagg_value, &my_integer_sum_drop_subagg_value, &my_integer_sum_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_total ), // 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 }; extern "C" a_v3_extfn_aggregate *my_integer_sum() { return &my_integer_sum_descriptor; }