/**
* call-seq:
* create_aggregate( db, name, args, step, finalize ) -> nil
*
* Defines a new aggregate function that may be invoked from within an SQL
* statement. The +args+ parameter specifies how many arguments the function
* expects--use -1 to specify variable arity.
*
* The +step+ parameter specifies a proc object that will be invoked for each
* row that the function processes. It should accept an opaque handle to the
* function object, followed by its expected arguments:
*
* step = proc do |func, *args|
* ...
* end
*
* The +finalize+ parameter specifies a proc object that will be invoked after
* all rows have been processed. This gives the function an opportunity to
* aggregate and finalize the results. It should accept a single parameter:
* the opaque function handle:
*
* finalize = proc do |func|
* ...
* end
*
* The function object is used when calling the #set_result,
* #set_result_error, #aggregate_context, and #aggregate_count methods.
*/
static VALUE
static_api_create_aggregate( VALUE module, VALUE db, VALUE name, VALUE n,
VALUE step, VALUE finalize )
{
sqlite *handle;
int result;
VALUE data;
GetDB( handle, db );
Check_Type( name, T_STRING );
Check_Type( n, T_FIXNUM );
if( !rb_obj_is_kind_of( step, rb_cProc ) )
{
rb_raise( rb_eArgError, "step must be a proc" );
}
if( !rb_obj_is_kind_of( finalize, rb_cProc ) )
{
rb_raise( rb_eArgError, "finalize must be a proc" );
}
/* FIXME: will the GC kill this before it is used? */
data = rb_ary_new3( 2, step, finalize );
result = sqlite_create_aggregate( handle,
StringValueCStr(name),
FIX2INT(n),
static_function_callback,
static_aggregate_finalize_callback,
(void*)data );
if( result != SQLITE_OK )
{
static_raise_db_error( result, "create aggregate %s(%d)",
StringValueCStr(name), FIX2INT(n) );
/* "raise" does not return */
}
return Qnil;
}