The SQSUM2 user-defined aggregate
The SQSUM2 user-defined aggregate is another version of the SQSUM1 aggregate.
(x1 + x2 + ... )2
where
each xi is one column value; that is, one aggregate
argument.However, the SQSUM2 aggregate takes advantage of the fact that this aggregate has a simple state. Because the database server automatically handles state management, the SQSUM2 aggregate can safely omit the INIT function.
/* SQSUM2 ITER support function on INTEGER */
mi_integer iter_sqsum2(state, value, fparam)
mi_integer state;
mi_integer value;
MI_FPARAM *fparam;
{
/* If 'state' is NULL, this is the first invocation.
* Just return 'value'.
*/
if ( mi_fp_argisnull(fparam, 0) )
return (value);
else /* add 'state' and 'value' together */
return (state + value);
}
/* SQSUM2 COMBINE support function on INTEGER */
mi_integer combine_sqsum2(state1, state2)
mi_integer state1, state2;
{
/* Return the new partial sum from two parallel partial
* sums
*/
return (iter_sqsum2(state1, state2));
}
/* SQSUM2 FINAL support function on INTEGER */
mi_integer final_sqsum2(state)
mi_integer state;
{
/* Calculate square of sum */
state *= state;
return (state);
}
The data type of the aggregate result is also the same as the aggregate state. Therefore, SQSUM2 is a simple binary operator and the FINAL support function is not needed to convert the data type of the final state. However, the SQSUM2 aggregate still does require a FINAL support function. The SQSUM2 algorithm involves a post-iteration calculation: it must square the final sum to obtain the aggregate return value. The FINAL function performs this final calculation and returns it as the aggregate result for the SQSUM2 aggregate.
Suppose that the ITER, COMBINE, and FINAL aggregate support functions for the SQSUM2 aggregate are compiled and linked into a shared-object module named sqsum.
On UNIX or Linux, the executable code for the SQSUM2 aggregate support functions would be in a shared library named sqsum.so.
CREATE AGGREGATE sqsum2
WITH (ITER = iter_sqsum2,
COMBINE = combine_sqsum2,
FINAL = final_sqsum2);
CREATE FUNCTION iter_sqsum2(state INTEGER, one_value INTEGER)
RETURNS INTEGER
WITH (HANDLESNULLS)
EXTERNAL NAME '/usr/udrs/aggs/sums/sqsum.so'
LANGUAGE C;
CREATE FUNCTION combine_sqsum2(state1 INTEGER, state2 INTEGER)
RETURNS INTEGER
EXTERNAL NAME '/usr/udrs/aggs/sums/sqsum.so'
LANGUAGE C;
CREATE FUNCTION final_sqsum2(state INTEGER)
RETURNS INTEGER
EXTERNAL NAME '/usr/udrs/aggs/sums/sqsum.so'
LANGUAGE C;
In Figure 3, the CREATE FUNCTION statement that registers the ITER support function requires the HANDLESNULLS routine modifier because the aggregate does not have an INIT support function.
SELECT SQSUM2(col3) FROM tab1;
With the rows that Figure 1 has inserted, the preceding query yields an INTEGER value of 10201, which is the same value that the SQSUM1 aggregate returned for these same rows.
Aggregate support function | SQL function name | C Function name |
---|---|---|
ITER | iter_sqsum2() | iter_sqsum2_complexnum() |
COMBINE | combine_sqsum2() | combine_sqsum2_complexnum() |
FINAL | final_sqsum2() | final_sqsum2_complexnum() |
/* SQSUM2 ITER support function for complexnum_t */
MI_ROW *iter_sqsum2_complexnum(state, value, fparam)
MI_ROW *state;
MI_ROW *value;
MI_FPARAM *fparam;
{
/* Compute the new partial sum using the complex_plus()
* function. Put the sum in a new MI_ROW, which
* complex_plus() allocates (and returns a pointer to)
*/
return (complex_plus(state, value, fparam));
}
/* SQSUM2 COMBINE support function for complexnum_t */
MI_ROW *combine_sqsum2_complexnum(state1, state2, fparam)
MI_ROW *state1, *state2;
MI_FPARAM *fparam;
{
MI_ROW *ret_state;
ret_state =
iter2_sqsum2_complexnum(state1, state2, fparam);
mi_free(state1);
mi_free(state2);
return (ret_state);
}
/* SQSUM2 FINAL support function for complexnum_t */
MI_ROW *final_sqsum2_complexnum(state)
MI_ROW *state;
{
MI_CONNECTION *conn;
MI_TYPEID *type_id;
MI_ROW_DESC *row_desc;
MI_ROW *ret_row;
MI_DATUM values[2];
mi_boolean nulls[2] = {MI_FALSE, MI_FALSE};
mi_real *real_value, *imag_value;
mi_integer real_len, imag_len;
mi_real sqsum_real, sqsum_imag;
/* Extract complex values from state row structure */
mi_value_by_name(state, "real_part",
(MI_DATUM *)&real_value, &real_len);
mi_value_by_name(state, "imaginary_part",
(MI_DATUM *)&imag_value, &imag_len);
/* Calculate square of sum */
sqsum_real = (*real_value) * (*real_value);
sqsum_imag = (*imag_value) * (*imag_value);
/* Put final result into 'values' array */
values[0] = (MI_DATUM)&sqsum_real;
values[1] = (MI_DATUM)&sqsum_imag;
/* Generate return row type */
conn = mi_open(NULL, NULL, NULL);
type_id = mi_typestring_to_id(conn, "complexnum_t");
row_desc = mi_row_desc_create(type_id);
ret_row = mi_row_create(conn, row_desc, values, nulls);
return (ret_row);
}
CREATE FUNCTION iter_sqsum2(state complexnum_t,
one_value complexnum_t)
RETURNS complexnum_t
WITH (HANDLESNULLS)
EXTERNAL NAME
'/usr/udrs/aggs/sums/sqsum.so(iter_sqsum2_complexnum)'
LANGUAGE C;
CREATE FUNCTION combine_sqsum2(state1 complexnum_t,
state2 complexnum_t)
RETURNS complexnum_t
EXTERNAL NAME
'/usr/udrs/aggs/sums/sqsum.so(combine_sqsum2_complexnum)'
LANGUAGE C;
CREATE FUNCTION final_sqsum2(state complexnum_t)
RETURNS complexnum_t
EXTERNAL NAME
'/usr/udrs/aggs/sums/sqsum.so(final_sqsum2_complexnum)'
LANGUAGE C;
SELECT SQSUM2(col2) FROM tab1;
ROW(817.96, 1204.09)