Skip to content

Support disabling checkpoint-on-close #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions sqlite3.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ _sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT);
}

static int
_sqlite3_db_config_no_ckpt_on_close(sqlite3 *db) {
int v;
return sqlite3_db_config(db, SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, &v);
}

#include <stdio.h>
#include <stdint.h>

Expand Down Expand Up @@ -1898,6 +1904,16 @@ func (c *SQLiteConn) SetFileControlInt(dbName string, op int, arg int) error {
return nil
}

// DBConfigNoCkptOnClose disables checkpointing on database close.
// See http://sqlite.org/c3ref/db_config.html
func (c *SQLiteConn) DBConfigNoCkptOnClose() error {
rv := C._sqlite3_db_config_no_ckpt_on_close(c.db)
if rv != C.SQLITE_OK {
return c.lastError()
}
return nil
}

// Close the statement.
func (s *SQLiteStmt) Close() error {
s.mu.Lock()
Expand Down
87 changes: 87 additions & 0 deletions sqlite3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package sqlite3

import (
"bytes"
"context"
"database/sql"
"database/sql/driver"
"errors"
Expand Down Expand Up @@ -1864,6 +1865,92 @@ func TestSetFileControlInt(t *testing.T) {
})
}

func TestDBConfigNoCkptOnClose(t *testing.T) {
fname := TempFilename(t)
defer os.Remove(fname)
db, err := sql.Open("sqlite3", fname)
if err != nil {
t.Fatal(err)
}
defer db.Close()

// Enable WAL mode.
if _, err := db.Exec(`PRAGMA journal_mode = wal`); err != nil {
t.Fatal(err)
}

// Write some data.
_, err = db.Exec("create table foo (department integer, profits integer)")
if err != nil {
t.Fatal("Failed to create table:", err)
}

// Confirm WAL file exists.
if _, err := os.Stat(fname + "-wal"); err != nil {
t.Fatal("Expected WAL file to exist", err)
}

// Close the database, and confirm WAL file is removed.
if err := db.Close(); err != nil {
t.Fatal("Failed to close database", err)
}
if _, err := os.Stat(fname + "-wal"); err == nil {
t.Fatal("Expected WAL file to be removed after close")
}

// Now do it again, but with the DBConfig option set.
db, err = sql.Open("sqlite3", fname)
if err != nil {
t.Fatal(err)
}
defer db.Close()

// Insert a record, confirm a WAL file appears.
if _, err := db.Exec(`insert into foo values (1, 2)`); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(fname + "-wal"); err != nil {
t.Fatal("Expected WAL file to exist", err)
}

// Disable checkpoint-on-close.
f := func(driverConn interface{}) error {
c := driverConn.(*SQLiteConn)
return c.DBConfigNoCkptOnClose()
}
conn, err := db.Conn(context.Background())
if err != nil {
t.Fatal(err)
}
if err := conn.Raw(f); err != nil {
t.Fatal(err)
}

// Read the SQLite file into a byte slice for comparison later.
bufPre, err := os.ReadFile(fname)
if err != nil {
t.Fatal(err)
}

// Close the database, and confirm WAL file is still present.
if err := db.Close(); err != nil {
t.Fatal("Failed to close database", err)
}
if _, err := os.Stat(fname + "-wal"); err != nil {
t.Fatal("Expected WAL file to be present after close", err)
}

// Confirm the SQLite file is the same as before since no checkpoint
// was performed.
bufPost, err := os.ReadFile(fname)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(bufPre, bufPost) {
t.Fatal("Expected SQLite file to be unchanged after close")
}
}

func TestNonColumnString(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
Expand Down
Loading