The aggregate UDF 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 "extfnapiv4.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 aggregate UDF, 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;
}