Skip to content

Commit 1cb802b

Browse files
committed
all: add TxnState
Part of a debugging attempt. Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
1 parent 15e15a3 commit 1cb802b

File tree

4 files changed

+87
-0
lines changed

4 files changed

+87
-0
lines changed

cgosqlite/cgosqlite.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,15 @@ func (db *DB) Checkpoint(dbName string, mode sqliteh.Checkpoint) (int, int, erro
131131
return int(nLog), int(nCkpt), errCode(res)
132132
}
133133

134+
func (db *DB) TxnState(schema string) sqliteh.TxnState {
135+
var cSchema *C.char
136+
if schema != "" {
137+
cSchema = C.CString(schema)
138+
defer C.free(unsafe.Pointer(cSchema))
139+
}
140+
return sqliteh.TxnState(C.sqlite3_txn_state(db.db, cSchema))
141+
}
142+
134143
func (db *DB) Prepare(query string, prepFlags sqliteh.PrepareFlags) (stmt sqliteh.Stmt, remainingQuery string, err error) {
135144
csql := C.CString(query)
136145
defer C.free(unsafe.Pointer(csql))

sqlite.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,18 @@ func BusyTimeout(sqlconn SQLConn, d time.Duration) error {
717717
})
718718
}
719719

720+
// TxnState calls sqlite3_txn_state on the underlying connection.
721+
func TxnState(sqlconn SQLConn, schema string) (state sqliteh.TxnState, err error) {
722+
return state, sqlconn.Raw(func(driverConn interface{}) error {
723+
c, ok := driverConn.(*conn)
724+
if !ok {
725+
return fmt.Errorf("sqlite.BusyTimeout: sql.Conn is not the sqlite driver: %T", driverConn)
726+
}
727+
state = c.db.TxnState(schema)
728+
return nil
729+
})
730+
}
731+
720732
// Checkpoint calls sqlite3_wal_checkpoint_v2 on the underlying connection.
721733
func Checkpoint(sqlconn SQLConn, dbName string, mode sqliteh.Checkpoint) (numFrames, numFramesCheckpointed int, err error) {
722734
err = sqlconn.Raw(func(driverConn interface{}) error {

sqlite_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,44 @@ func TestTrace(t *testing.T) {
567567
expectEv(ctx, "INSERT INTO t2 (c) VALUES (1)", "UNIQUE constraint failed")
568568
}
569569

570+
func TestTxnState(t *testing.T) {
571+
dbFile := t.TempDir() + "/test.db"
572+
db, err := sql.Open("sqlite3", "file:"+dbFile)
573+
if err != nil {
574+
t.Fatal(err)
575+
}
576+
if _, err := db.Exec("PRAGMA journal_mode=WAL"); err != nil {
577+
t.Fatal(err)
578+
}
579+
580+
ctx := context.Background()
581+
sqlConn, err := db.Conn(ctx)
582+
if err != nil {
583+
t.Fatal(err)
584+
}
585+
if state, err := TxnState(sqlConn, ""); err != nil {
586+
t.Fatal(err)
587+
} else if state != sqliteh.SQLITE_TXN_NONE {
588+
t.Errorf("state=%v, want SQLITE_TXN_NONE", state)
589+
}
590+
if err := ExecScript(sqlConn, "BEGIN; CREATE TABLE t (c);"); err != nil {
591+
t.Fatal(err)
592+
}
593+
if state, err := TxnState(sqlConn, ""); err != nil {
594+
t.Fatal(err)
595+
} else if state != sqliteh.SQLITE_TXN_WRITE {
596+
t.Errorf("state=%v, want SQLITE_TXN_WRITE", state)
597+
}
598+
if err := ExecScript(sqlConn, "COMMIT; BEGIN; SELECT * FROM (t);"); err != nil {
599+
t.Fatal(err)
600+
}
601+
if state, err := TxnState(sqlConn, ""); err != nil {
602+
t.Fatal(err)
603+
} else if state != sqliteh.SQLITE_TXN_READ {
604+
t.Errorf("state=%v, want SQLITE_TXN_READ", state)
605+
}
606+
}
607+
570608
func BenchmarkPersist(b *testing.B) {
571609
ctx := context.Background()
572610
db := openTestDB(b)

sqliteh/sqliteh.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ type DB interface {
4747
BusyTimeout(time.Duration)
4848
// Checkpoint is sqlite3_wal_checkpoint_v2.
4949
Checkpoint(db string, mode Checkpoint) (numFrames, numFramesCheckpointed int, err error)
50+
// TxnState is sqlite3_txn_state.
51+
TxnState(schema string) TxnState
5052
}
5153

5254
// Stmt is an sqlite3_stmt* database connection object.
@@ -354,6 +356,32 @@ func (mode Checkpoint) String() string {
354356
}
355357
}
356358

359+
// TxnState is a transaction state.
360+
// It is used by sqlite3_txn_state.
361+
//
362+
// https://sqlite.org/c3ref/txn_state.html
363+
type TxnState int
364+
365+
const (
366+
SQLITE_TXN_NONE TxnState = 0
367+
SQLITE_TXN_READ TxnState = 1
368+
SQLITE_TXN_WRITE TxnState = 2
369+
)
370+
371+
func (state TxnState) String() string {
372+
switch state {
373+
default:
374+
var buf [20]byte
375+
return "SQLITE_TXN_UNKNOWN(" + string(itoa(buf[:], int64(state))) + ")"
376+
case SQLITE_TXN_NONE:
377+
return "SQLITE_TXN_NONE"
378+
case SQLITE_TXN_READ:
379+
return "SQLITE_TXN_READ"
380+
case SQLITE_TXN_WRITE:
381+
return "SQLITE_TXN_WRITE"
382+
}
383+
}
384+
357385
// ErrCode is an SQLite error code as a Go error.
358386
// It must not be one of the status codes SQLITE_OK, SQLITE_ROW, or SQLITE_DONE.
359387
type ErrCode Code

0 commit comments

Comments
 (0)