Aggregate window functions don't call xFinal

I just released a new API in my package to call sqlite3_create_window_function. Most everything works, but I'm noticing that the xFinal callback is not being called.

To reproduce:

git clone -b window-final https://github.com/zombiezen/go-sqlite.git &&
cd go-sqlite &&
go test -run=TestWindowFunc

I've stepped through with Delve to trace data passing and AFAICT, sqlite3_create_window_function is receiving the correct callback.

This doesn't appear to be an issue with upstream SQLite, so I'm suspecting this library. I used the following (roughly equivalent) C program to test with SQLite 3.38.05 and it behaves as I expect:

#include <assert.h>
#include <stdio.h>
#include "sqlite3.h"

static void sumintStep(
  sqlite3_context *ctx, 
  int nArg, 
  sqlite3_value *apArg[]
){
  sqlite3_int64 *pInt;

  assert( nArg==1 );
  if( sqlite3_value_type(apArg[0])!=SQLITE_INTEGER ){
    sqlite3_result_error(ctx, "invalid argument", -1);
    return;
  }
  fprintf(stderr, "STEP\n");
  pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));
  if( pInt ){
    *pInt += sqlite3_value_int64(apArg[0]);
  }
}

static void sumintInverse(
  sqlite3_context *ctx, 
  int nArg, 
  sqlite3_value *apArg[]
){
  sqlite3_int64 *pInt;
  assert( sqlite3_value_type(apArg[0])==SQLITE_INTEGER );
  pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));
  *pInt -= sqlite3_value_int64(apArg[0]);
}

static void sumintFinal(sqlite3_context *ctx){
  fprintf(stderr, "FINAL\n");
  sqlite3_int64 res = 0;
  sqlite3_int64 *pInt;
  pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);
  if( pInt ) res = *pInt;
  sqlite3_result_int64(ctx, res);
}

static void sumintValue(sqlite3_context *ctx){
  sqlite3_int64 res = 0;
  sqlite3_int64 *pInt;
  pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);
  if( pInt ) res = *pInt;
  sqlite3_result_int64(ctx, res);
}

static void sumintDestroy(void *pApp){
  fprintf(stderr, "DESTROY %#x\n", pApp);
}

int register_sumint(sqlite3 *db){
  return sqlite3_create_window_function(db, "sumint", 1, SQLITE_UTF8, 0,
      sumintStep, sumintFinal, sumintValue, sumintInverse, sumintDestroy
  );
}

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  int i;
  for(i=0; i<argc; i++){
    printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
  }
  printf("\n");
  return 0;
}

int main() {
  sqlite3* db;
  if (sqlite3_open(":memory:", &db)) {
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  if (register_sumint(db)) {
    fprintf(stderr, "Can't register function: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  if (sqlite3_exec(db, "CREATE TABLE t3(x, y);", NULL, 0, NULL)) {
    fprintf(stderr, "CREATE TABLE: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  if (sqlite3_exec(db, "INSERT INTO t3 VALUES('a', 4), ('b', 5), ('c', 3), ('d', 8), ('e', 1);", NULL, 0, NULL)) {
    fprintf(stderr, "INSERT: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  if (sqlite3_exec(db, "SELECT x, sumint(y) OVER ( ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS sum_y FROM t3 ORDER BY x;", callback, 0, NULL)) {
    fprintf(stderr, "SELECT: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  fprintf(stderr, "SELECT finished\n");
  sqlite3_close(db);
  return 0;
}
Edited by Roxy Light