Hello,

After consulting the php-sources I could hack the tclsqlite.c file
myself to add aggregation capabilities to tcl, this should go into the
next release:

the diff:

2c2
< ** 2001 September 15
---
> ** 2004 June 8 added aggregate function by Dr. Detlef Groth (dgroth at gmx.de)
43a44,54
> /*
> ** New SQL aggregate functions can be created as TCL scripts.  Each such aggregate 
> function
> ** is described by an instance of the following structure.
> */
> typedef struct SqlAggrFunc SqlAggrFunc;
> struct SqlAggrFunc {
>     Tcl_Interp *interp;   /* The TCL interpret to execute the function */
>     char *zScriptStep;        /* The script to be run foreach row*/
>     char *zScriptFine;        /* The script to be run at the end*/
>     SqlFunc *pNext;       /* Next function on the list of them all */
> };
399a411,447
> static void tclSqlAggStep(sqlite_func *context, int argc, const char **argv){
>     SqlAggrFunc *p = sqlite_user_data(context);
>     Tcl_DString cmd;
>     int i;
>     int rc;
>     int zargc , zargs;
>     zargc = argc ;
>     Tcl_DStringInit(&cmd);
>     Tcl_DStringAppend(&cmd, p->zScriptStep, -1);
>     for(i=0; i<(zargc); i++){
>         Tcl_DStringAppendElement(&cmd, argv[0] ? argv[i] : "");
>     }
>     rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
>   if( rc ){
>     sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1); 
>   }else{
>     sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
>   }
> }
> 
> /** This routine is called to evaluate an SQL aggregate implemented
> ** using TCL script.
> */
> static void tclSqlAggFine(sqlite_func *context){
>     SqlAggrFunc *p = sqlite_user_data(context);
>     int rc;
>     Tcl_DString cmd;
>     Tcl_DStringInit(&cmd);
>     Tcl_DStringAppend(&cmd, p->zScriptFine, -1);
>     rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
>     if( rc ){
>         sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1); 
>     }else{
>         sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
>     }
> }
> 
493c541
<     "errorcode",          "eval",                   "function",
---
>     "errorcode",          "eval",                   "function", "aggregate",
502c550
<     DB_ERRORCODE,         DB_EVAL,                   DB_FUNCTION,
---
>     DB_ERRORCODE,         DB_EVAL,                   DB_FUNCTION,  DB_AGGREGATE,
864a913,944
>   }
>   /*
>   **     $db aggregate NAME SCRIPTSTEP SCRIPTFINALIZE
>   **
>   ** Create a new SQL aggregate function called NAME.  Whenever that function is
>   ** called, invoke SCRIPTINIT for each row and SCRIPTFINALIZE at the end to 
> evaluate the function.
>   */
>   case DB_AGGREGATE: {
>       SqlAggrFunc *pFunc;
>       char *zName;
>       char *zScript;
>       char *zScriptFine;
>       int nScript1;
>       int nScript2;
>       if( objc!=5 ){
>           Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPTSTEP SCRIPTFINALIZE");
>           return TCL_ERROR;
>       }
>       zName = Tcl_GetStringFromObj(objv[2], 0);
>       zScript = Tcl_GetStringFromObj(objv[3], &nScript1);
>       zScriptFine = Tcl_GetStringFromObj(objv[4], &nScript2);
>       pFunc = (SqlAggrFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript1 +nScript2 + 1 );
>       if( pFunc==0 ) return TCL_ERROR;
>       pFunc->interp = interp;
>       pFunc->zScriptStep = (char*)&pFunc[1];
>       pFunc->pNext = pDb->pFunc;
>       pFunc->zScriptFine = (char*)&pFunc[2];
>       strcpy(pFunc->zScriptStep, zScript);
>       strcpy(pFunc->zScriptFine, zScriptFine);
>       sqlite_create_aggregate(pDb->db, zName, -1, tclSqlAggStep, tclSqlAggFine, 
> pFunc);
>       sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC);
>       break;

Here comes an usage example in tcl:
load tclsqlite-stub-aggr.dll
sqlite sql d:/data/yaspo2004bt.sqlite
# the old function interface
sql function median Median
# the new aggregate interface
sql aggregate medianAgg MedianAggStep MedianAggFin
set l [list]
proc Median {value} {
  global l
  lappend l $value 
  # crude and slow but works
  return  [lindex [lsort -integer $l] [expr round([llength $l] / 2)]]
}
set v [lindex [sql eval "select median(Size) from tensembl"] end]
tk_messageBox -type ok -title "Info!" -message "Result: $v"
set l [list]
set v ""
proc MedianAggStep {args} {
    global l
    lappend l [lindex $args 0]
    return 0
}
proc MedianAggFin {} {
     global l
     # this is just executed ones
     return [lindex [lsort -integer $l] [expr round([llength $l] / 2)]]
}
array unset val
sql eval "select medianAgg(Size) from tensembl" val {
  # to get the key
  set key [array names val medianA*]
  tk_messageBox -type ok -title "Info!" -message "Result Aggregate: $val($key)"
}

regards,
Detlef

-- 
Dr. Detlef Groth
Max-Planck-Institut
fuer Molekulare Genetik
Ihnestr. 63/73
D-14195 Berlin
Tel.: + 49 30 - 8413 1235

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to