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