The aggregate UDF context structure, a_v3_extfn_aggregate_context, has exactly the same set of callback function pointers as the scalar UDF context structure.
In addition, it has a read/write _user_data pointer just like the scalar UDF context, and a set of read-only data fields that describe the current usage and location. Each unique instance of the UDF within a statement has one aggregate UDF context instance that is passed to each of the functions specified within the aggregate UDF descriptor structure when they are called. The aggregate context structure is defined as:
typedef struct a_v3_extfn_aggregate_context – One created for each instance of an external function referenced within a query. If used within a parallelized subtree within a query, there is a separate context for parallel subtree.
Callbacks available via the context – Common arguments to the callback routines include:
The context must call get_value before get_piece, but needs to call get_piece only if piece_len is less than total_len.
short (SQL_CALLBACK *get_value)( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value ); short (SQL_CALLBACK *get_piece)( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value, a_sql_uint32 offset );
Determining whether an argument is a constant – The UDF can ask whether a given argument is a constant. This can be useful, for example, to allow work to be done once at the first call to the _next_value function rather than for every call to the _next_value function.
short (SQL_CALLBACK *get_value_is_constant)( void * arg_handle, a_sql_uint32 arg_num, a_sql_uint32 * value_is_constant );
Returning a null value – To return a null value, set "data" to NULL in an_extfn_value. The total_len field is ignored on calls to set_value, the data supplied becomes the value of the argument if append is FALSE; otherwise, the data is appended to the current value of the argument. It is expected that set_value is called with append=FALSE for an argument before being called with append=TRUE for the same argument. The append field is ignored for fixed-length data types (in other words, all numeric data types).
short (SQL_CALLBACK *set_value)( void * arg_handle, an_extfn_value *value, short append );
Determining whether the statement was interrupted – If a UDF entry point performs work for an extended period of time (many seconds), then it should, if possible, call the get_is_cancelled callback every second or two to see if the user has interrupted the current statement. If the statement has been interrupted, a nonzero value is returned, and the UDF entry point should then immediately perform. Eventually, the _finish_extfn function is called to do any necessary cleanup, but no other UDF entry points are subsequently called.
a_sql_uint32 (SQL_CALLBACK *get_is_cancelled)(a_v3_extfn_aggregate_context * cntxt);
Sending error messages – If a UDF entry point encounters some error that should result in an error message being sent back to the user and the current statement being shut down, the set_error callback routine should be called. set_error causes the current statement to roll back; the user sees Error from external UDF: <error_desc_string>, and the SQLCODE is the negated form of <error_number>. After a call to set_error, the UDF entry point immediately performs a return. Eventually, _finish_extfn is called to perform any necessary cleanup, but no other UDF entry points are subsequently called.
void (SQL_CALLBACK *set_error)( a_v3_extfn_aggregate_context * cntxt, a_sql_uint32 error_number, // use error_number values >17000 & <100000 const char * error_desc_string );
Writing messages to the message log – Messages longer than 255 bytes may be truncated.
void (SQL_CALLBACK *log_message)( const char *msg, short msg_length );
Converting one data type to another – for input:
For output:
short (SQL_CALLBACK *convert_value)( an_extfn_value *input, an_extfn_value *output );
Fields reserved for future use – These are reserved for future use:
void * reserved1; void * reserved2; void * reserved3; void * reserved4; void * reserved5;
Data available from the context – This data pointer can be filled in by any usage with any context data the external routine requires. The UDF allocates and deallocates this memory. A single instance of _user_data is active for each statement. Do not use this memory for intermediate result values.
void * _user_data;
Currently active calculation context – UDFs should use this memory location to store intermediate values that calculate the aggregate. This memory is allocated by the server based on the size requested in the a_v3_extfn_aggregate. Intermediate calculations must be stored in this memory, since the engine may perform simultaneous calculations over more than one group. Before each UDF entry point, the server ensures that the correct context data is active.
void * _user_calculation_context;
Other available aggregate information – Available at all external function entry points, including start_extfn. Zero indicates an unknown or not-applicable value. Estimated average number of rows per partition or group.
a_sql_uint64 _max_rows_in_frame; – Calculates the maximum number of rows defined in the window frame. For range-based windows, this indicates unique values. Zero indicates an unknown or not-applicable value.
a_sql_uint64 _estimated_rows_per_partition; – Displays the estimated average number of rows per partition or group. 0 indicates an unknown or not-applicable value.
a_sql_uint32 _is_used_as_a_superaggregate; – Identifies whether this instance is a normal aggregate or a superaggregate. Returns a result of 0 if the instance is a normal aggregate.
Determining window specifications – Window specifications if a window is present on the query:
a_sql_uint32 _is_window_used; – Determines if the statement is windowed.
a_sql_uint32 _window_has_unbounded_preceding; – A return value of 0 indicates the window does not have unbounded preceding.
a_sql_uint32 _window_contains_current_row; – A return value of 0 indicates the window does not contain the current row.
a_sql_uint32 _window_is_range_based; – If the return code is 1, the window is range-based. If the return code is 0, the window is row-based.
Available at reset_extfn() calls – Returns the actual number of rows in current partition, or 0 for nonwindowed aggregate.
a_sql_uint64 _num_rows_in_partition;
Available only at evaluate_extfn() calls for windowed aggregates – Currently evaluated row number in partition (starting with 1). This is useful during the evaluation phase of unbounded windows.
a_sql_uint64 _result_row_from_start_of_partition;
Closing syntax – Complete the context with:
//---------- For Server Internal Use Only ---------- void * _for_server_internal_use; } a_v3_extfn_aggregate_context;