Skip to content

Commit 7205526

Browse files
authored
Merge pull request #30 from rqlite/SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
Support disabling checkpoint-on-close
2 parents 0c35ea2 + 1fd986c commit 7205526

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

sqlite3.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ _sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
8484
return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT);
8585
}
8686
87+
static int
88+
_sqlite3_db_config_no_ckpt_on_close(sqlite3 *db) {
89+
int v;
90+
return sqlite3_db_config(db, SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, &v);
91+
}
92+
8793
#include <stdio.h>
8894
#include <stdint.h>
8995
@@ -1898,6 +1904,16 @@ func (c *SQLiteConn) SetFileControlInt(dbName string, op int, arg int) error {
18981904
return nil
18991905
}
19001906

1907+
// DBConfigNoCkptOnClose disables checkpointing on database close.
1908+
// See http://sqlite.org/c3ref/db_config.html
1909+
func (c *SQLiteConn) DBConfigNoCkptOnClose() error {
1910+
rv := C._sqlite3_db_config_no_ckpt_on_close(c.db)
1911+
if rv != C.SQLITE_OK {
1912+
return c.lastError()
1913+
}
1914+
return nil
1915+
}
1916+
19011917
// Close the statement.
19021918
func (s *SQLiteStmt) Close() error {
19031919
s.mu.Lock()

sqlite3_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package sqlite3
1010

1111
import (
1212
"bytes"
13+
"context"
1314
"database/sql"
1415
"database/sql/driver"
1516
"errors"
@@ -1864,6 +1865,92 @@ func TestSetFileControlInt(t *testing.T) {
18641865
})
18651866
}
18661867

1868+
func TestDBConfigNoCkptOnClose(t *testing.T) {
1869+
fname := TempFilename(t)
1870+
defer os.Remove(fname)
1871+
db, err := sql.Open("sqlite3", fname)
1872+
if err != nil {
1873+
t.Fatal(err)
1874+
}
1875+
defer db.Close()
1876+
1877+
// Enable WAL mode.
1878+
if _, err := db.Exec(`PRAGMA journal_mode = wal`); err != nil {
1879+
t.Fatal(err)
1880+
}
1881+
1882+
// Write some data.
1883+
_, err = db.Exec("create table foo (department integer, profits integer)")
1884+
if err != nil {
1885+
t.Fatal("Failed to create table:", err)
1886+
}
1887+
1888+
// Confirm WAL file exists.
1889+
if _, err := os.Stat(fname + "-wal"); err != nil {
1890+
t.Fatal("Expected WAL file to exist", err)
1891+
}
1892+
1893+
// Close the database, and confirm WAL file is removed.
1894+
if err := db.Close(); err != nil {
1895+
t.Fatal("Failed to close database", err)
1896+
}
1897+
if _, err := os.Stat(fname + "-wal"); err == nil {
1898+
t.Fatal("Expected WAL file to be removed after close")
1899+
}
1900+
1901+
// Now do it again, but with the DBConfig option set.
1902+
db, err = sql.Open("sqlite3", fname)
1903+
if err != nil {
1904+
t.Fatal(err)
1905+
}
1906+
defer db.Close()
1907+
1908+
// Insert a record, confirm a WAL file appears.
1909+
if _, err := db.Exec(`insert into foo values (1, 2)`); err != nil {
1910+
t.Fatal(err)
1911+
}
1912+
if _, err := os.Stat(fname + "-wal"); err != nil {
1913+
t.Fatal("Expected WAL file to exist", err)
1914+
}
1915+
1916+
// Disable checkpoint-on-close.
1917+
f := func(driverConn interface{}) error {
1918+
c := driverConn.(*SQLiteConn)
1919+
return c.DBConfigNoCkptOnClose()
1920+
}
1921+
conn, err := db.Conn(context.Background())
1922+
if err != nil {
1923+
t.Fatal(err)
1924+
}
1925+
if err := conn.Raw(f); err != nil {
1926+
t.Fatal(err)
1927+
}
1928+
1929+
// Read the SQLite file into a byte slice for comparison later.
1930+
bufPre, err := os.ReadFile(fname)
1931+
if err != nil {
1932+
t.Fatal(err)
1933+
}
1934+
1935+
// Close the database, and confirm WAL file is still present.
1936+
if err := db.Close(); err != nil {
1937+
t.Fatal("Failed to close database", err)
1938+
}
1939+
if _, err := os.Stat(fname + "-wal"); err != nil {
1940+
t.Fatal("Expected WAL file to be present after close", err)
1941+
}
1942+
1943+
// Confirm the SQLite file is the same as before since no checkpoint
1944+
// was performed.
1945+
bufPost, err := os.ReadFile(fname)
1946+
if err != nil {
1947+
t.Fatal(err)
1948+
}
1949+
if !bytes.Equal(bufPre, bufPost) {
1950+
t.Fatal("Expected SQLite file to be unchanged after close")
1951+
}
1952+
}
1953+
18671954
func TestNonColumnString(t *testing.T) {
18681955
db, err := sql.Open("sqlite3", ":memory:")
18691956
if err != nil {

0 commit comments

Comments
 (0)