@@ -100,6 +100,8 @@ int _sqlite3_create_function(
100
100
}
101
101
102
102
void callbackTrampoline(sqlite3_context*, int, sqlite3_value**);
103
+ void stepTrampoline(sqlite3_context*, int, sqlite3_value**);
104
+ void doneTrampoline(sqlite3_context*);
103
105
104
106
int compareTrampoline(void*, int, char*, int, char*);
105
107
int commitHookTrampoline(void*);
@@ -477,6 +479,131 @@ func sqlite3CreateFunction(db *C.sqlite3, zFunctionName *C.char, nArg C.int, eTe
477
479
return C ._sqlite3_create_function (db , zFunctionName , nArg , eTextRep , C .uintptr_t (pApp ), (* [0 ]byte )(unsafe .Pointer (xFunc )), (* [0 ]byte )(unsafe .Pointer (xStep )), (* [0 ]byte )(unsafe .Pointer (xFinal )))
478
480
}
479
481
482
+ // RegisterAggregator makes a Go type available as a SQLite aggregation function.
483
+ //
484
+ // Because aggregation is incremental, it's implemented in Go with a
485
+ // type that has 2 methods: func Step(values) accumulates one row of
486
+ // data into the accumulator, and func Done() ret finalizes and
487
+ // returns the aggregate value. "values" and "ret" may be any type
488
+ // supported by RegisterFunc.
489
+ //
490
+ // RegisterAggregator takes as implementation a constructor function
491
+ // that constructs an instance of the aggregator type each time an
492
+ // aggregation begins. The constructor must return a pointer to a
493
+ // type, or an interface that implements Step() and Done().
494
+ //
495
+ // The constructor function and the Step/Done methods may optionally
496
+ // return an error in addition to their other return values.
497
+ //
498
+ // See _example/go_custom_funcs for a detailed example.
499
+ func (c * SQLiteConn ) RegisterAggregator (name string , impl interface {}, pure bool ) error {
500
+ var ai aggInfo
501
+ ai .constructor = reflect .ValueOf (impl )
502
+ t := ai .constructor .Type ()
503
+ if t .Kind () != reflect .Func {
504
+ return errors .New ("non-function passed to RegisterAggregator" )
505
+ }
506
+ if t .NumOut () != 1 && t .NumOut () != 2 {
507
+ return errors .New ("SQLite aggregator constructors must return 1 or 2 values" )
508
+ }
509
+ if t .NumOut () == 2 && ! t .Out (1 ).Implements (reflect .TypeOf ((* error )(nil )).Elem ()) {
510
+ return errors .New ("Second return value of SQLite function must be error" )
511
+ }
512
+ if t .NumIn () != 0 {
513
+ return errors .New ("SQLite aggregator constructors must not have arguments" )
514
+ }
515
+
516
+ agg := t .Out (0 )
517
+ switch agg .Kind () {
518
+ case reflect .Ptr , reflect .Interface :
519
+ default :
520
+ return errors .New ("SQlite aggregator constructor must return a pointer object" )
521
+ }
522
+ stepFn , found := agg .MethodByName ("Step" )
523
+ if ! found {
524
+ return errors .New ("SQlite aggregator doesn't have a Step() function" )
525
+ }
526
+ step := stepFn .Type
527
+ if step .NumOut () != 0 && step .NumOut () != 1 {
528
+ return errors .New ("SQlite aggregator Step() function must return 0 or 1 values" )
529
+ }
530
+ if step .NumOut () == 1 && ! step .Out (0 ).Implements (reflect .TypeOf ((* error )(nil )).Elem ()) {
531
+ return errors .New ("type of SQlite aggregator Step() return value must be error" )
532
+ }
533
+
534
+ stepNArgs := step .NumIn ()
535
+ start := 0
536
+ if agg .Kind () == reflect .Ptr {
537
+ // Skip over the method receiver
538
+ stepNArgs --
539
+ start ++
540
+ }
541
+ if step .IsVariadic () {
542
+ stepNArgs --
543
+ }
544
+ for i := start ; i < start + stepNArgs ; i ++ {
545
+ conv , err := callbackArg (step .In (i ))
546
+ if err != nil {
547
+ return err
548
+ }
549
+ ai .stepArgConverters = append (ai .stepArgConverters , conv )
550
+ }
551
+ if step .IsVariadic () {
552
+ conv , err := callbackArg (t .In (start + stepNArgs ).Elem ())
553
+ if err != nil {
554
+ return err
555
+ }
556
+ ai .stepVariadicConverter = conv
557
+ // Pass -1 to sqlite so that it allows any number of
558
+ // arguments. The call helper verifies that the minimum number
559
+ // of arguments is present for variadic functions.
560
+ stepNArgs = - 1
561
+ }
562
+
563
+ doneFn , found := agg .MethodByName ("Done" )
564
+ if ! found {
565
+ return errors .New ("SQlite aggregator doesn't have a Done() function" )
566
+ }
567
+ done := doneFn .Type
568
+ doneNArgs := done .NumIn ()
569
+ if agg .Kind () == reflect .Ptr {
570
+ // Skip over the method receiver
571
+ doneNArgs --
572
+ }
573
+ if doneNArgs != 0 {
574
+ return errors .New ("SQlite aggregator Done() function must have no arguments" )
575
+ }
576
+ if done .NumOut () != 1 && done .NumOut () != 2 {
577
+ return errors .New ("SQLite aggregator Done() function must return 1 or 2 values" )
578
+ }
579
+ if done .NumOut () == 2 && ! done .Out (1 ).Implements (reflect .TypeOf ((* error )(nil )).Elem ()) {
580
+ return errors .New ("second return value of SQLite aggregator Done() function must be error" )
581
+ }
582
+
583
+ conv , err := callbackRet (done .Out (0 ))
584
+ if err != nil {
585
+ return err
586
+ }
587
+ ai .doneRetConverter = conv
588
+ ai .active = make (map [int64 ]reflect.Value )
589
+ ai .next = 1
590
+
591
+ // ai must outlast the database connection, or we'll have dangling pointers.
592
+ c .aggregators = append (c .aggregators , & ai )
593
+
594
+ cname := C .CString (name )
595
+ defer C .free (unsafe .Pointer (cname ))
596
+ opts := C .SQLITE_UTF8
597
+ if pure {
598
+ opts |= C .SQLITE_DETERMINISTIC
599
+ }
600
+ rv := sqlite3CreateFunction (c .db , cname , C .int (stepNArgs ), C .int (opts ), newHandle (c , & ai ), nil , C .stepTrampoline , C .doneTrampoline )
601
+ if rv != C .SQLITE_OK {
602
+ return c .lastError ()
603
+ }
604
+ return nil
605
+ }
606
+
480
607
// AutoCommit return which currently auto commit or not.
481
608
func (c * SQLiteConn ) AutoCommit () bool {
482
609
return int (C .sqlite3_get_autocommit (c .db )) != 0
0 commit comments