void db_primitive_close()
{
    purge_buckets();

    // Close the handle to free memory
    sqlite3_close(handle);
}
void db_primitive_transaction_end()
{
    char *errmsg;
    char buf[80];
    purge_buckets();
    sprintf( buf, "COMMIT TRANSACTION" );
    int retval = sqlite3_exec( handle, buf,0,0,&errmsg);
    if( retval )
        printf("sqlite3_exec(COMMIT TRANSACTION) FAILED %s\n", errmsg );
}
void db_primitive_create_indexes()
{
    char buf[200];
    purge_buckets();
    report( "Create positions index" );
    sprintf( buf, "CREATE INDEX IF NOT EXISTS idx2 ON positions(position_hash)");
    int retval = sqlite3_exec(handle,buf,0,0,0);
    report( "Create positions index end" );
    if( retval )
    {
        printf( "sqlite3_exec(%s) FAILED\n", buf );
        return;
    }
    report( "Create games index");
    retval = sqlite3_exec(handle,"CREATE INDEX IF NOT EXISTS idx3 ON games(game_id)",0,0,0);
    report( "Create games index end");
    if( retval )
    {
        printf("sqlite3_exec(CREATE INDEX games) FAILED\n");
    }
}
// Returns bool ok
bool db_primitive_transaction_end()
{
    bool ok = purge_buckets();
    ProgressBar prog( "Creating database", "Completing save", window_parent );
    if( ok )
    {
        char *errmsg=NULL;
        int retval = sqlite3_exec( handle, "COMMIT TRANSACTION", 0, 0, &errmsg);
        bool ok = (retval==0);
        if( retval && errmsg )
        {
            char buf[1000];
            sprintf( buf, "Database error: sqlite3_exec(COMMIT TRANSACTION) FAILED %s", errmsg );
            error_msg = buf;
        }
        else if( !ok )
        {
            error_msg = "Database error: sqlite3_exec(COMMIT TRANSACTION) FAILED";
        }
    }
    return ok;
}
void db_primitive_create_indexes_multi()
{
    purge_buckets();
    for( int i=0; i<NBR_BUCKETS; i++ )
    {
        char buf[200];
        sprintf( buf, "Create positions_%d index", i );
        report( buf );
        sprintf( buf, "CREATE INDEX IF NOT EXISTS idx%d ON positions_%d(position_hash)",i,i);
        int retval = sqlite3_exec(handle,buf,0,0,0);
        if( retval )
        {
            printf( "sqlite3_exec(%s) FAILED\n", buf );
            return;
        }
    }
    report( "Create games index");
    int retval = sqlite3_exec(handle,"CREATE INDEX IF NOT EXISTS idx_games ON games(game_id)",0,0,0);
    report( "Create games index end");
    if( retval )
    {
        printf("sqlite3_exec(CREATE INDEX games) FAILED\n");
    }
}
bool db_primitive_flush()
{
    bool ok=purge_buckets(true);
    return ok;
}
// Returns bool ok
bool db_primitive_create_indexes()
{
    ProgressBar prog( "Creating database, step 4 of 4", "Indexing positions", window_parent );
    DebugPrintfTime turn_on_time_reporting;
    bool ok = purge_buckets();
    if( !ok )
        return false;
    cprintf( "Create games index\n");
    int retval = sqlite3_exec(handle,"CREATE INDEX IF NOT EXISTS idx_games ON games(game_id)",0,0,0);
    cprintf( "Create games index end\n");
    if( retval )
    {
        error_msg = "Database error: sqlite3_exec(CREATE INDEX games) FAILED";
        return false;
    }
    if( prog.Percent(1) )
    {
        error_msg = "cancel";
        return false;
    }
    cprintf( "Create games(white) index\n");
    retval = sqlite3_exec(handle,"CREATE INDEX IF NOT EXISTS idx_white ON games(white)",0,0,0);
    if( retval )
    {
        error_msg = "Database error: sqlite3_exec() FAILED 1";
        return false;
    }
    if( prog.Percent(2) )
    {
        error_msg = "cancel";
        return false;
    }
    cprintf( "Create games(black) index\n");
    retval = sqlite3_exec(handle,"CREATE INDEX IF NOT EXISTS idx_black ON games(black)",0,0,0);
    if( retval )
    {
        error_msg = "Database error: sqlite3_exec() FAILED 2";
        return false;
    }
    if( prog.Percent(3) )
    {
        error_msg = "cancel";
        return false;
    }
    for( int i=0; i<NBR_BUCKETS; i++ )
    {
        if( prog.Permill( 30 + (i*970) / NBR_BUCKETS ) )
        {
            error_msg = "cancel";
            return false;
        }
        char buf[200];
        if( i%100 == 0 )
            cprintf( "Create idx%d begin\n", i );
        sprintf( buf, "CREATE INDEX IF NOT EXISTS idx%d ON positions_%d(position_hash,game_id)",i,i);
        retval = sqlite3_exec(handle,buf,0,0,0);
        if( i%100 == 0 )
            cprintf( "Create idx%d end\n", i );
        if( retval )
        {
            error_msg = "Database error: sqlite3_exec() FAILED 3";
            return false;
        }
    }
    return true;
}