diff --git a/blob.go b/blob.go index 742b833..5a0ee61 100644 --- a/blob.go +++ b/blob.go @@ -25,6 +25,7 @@ var _ io.ReadWriteSeeker = &Blob{} // // https://www.sqlite.org/c3ref/blob_open.html func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, error) { + c.checkInterrupt() defer c.arena.reset() blobPtr := c.arena.new(ptrlen) dbPtr := c.arena.string(db) diff --git a/conn.go b/conn.go index 01cc1a3..60b1ec6 100644 --- a/conn.go +++ b/conn.go @@ -87,6 +87,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { } } + c.arena.reset() pragmaPtr := c.arena.string(pragmas.String()) r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0) if err := c.module.error(r[0], handle, pragmas.String()); err != nil { @@ -145,23 +146,6 @@ func (c *Conn) Exec(sql string) error { return c.error(r[0]) } -// MustPrepare calls [Conn.Prepare] and panics on error, -// a nil Stmt, or a non-empty tail. -func (c *Conn) MustPrepare(sql string) *Stmt { - s, tail, err := c.PrepareFlags(sql, 0) - if err != nil { - panic(err) - } - if s == nil { - panic(emptyErr) - } - if !emptyStatement(tail) { - s.Close() - panic(tailErr) - } - return s -} - // Prepare calls [Conn.PrepareFlags] with no flags. func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) { return c.PrepareFlags(sql, 0) @@ -263,7 +247,7 @@ func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) { // Creating an uncompleted SQL statement prevents SQLite from ignoring // an interrupt that comes before any other statements are started. if c.pending == nil { - c.pending = c.MustPrepare(`SELECT 1 UNION ALL SELECT 2`) + c.pending, _, _ = c.Prepare(`SELECT 1 UNION ALL SELECT 2`) } c.pending.Step() @@ -305,15 +289,18 @@ func (c *Conn) checkInterrupt() bool { // Pragma executes a PRAGMA statement and returns any results. // // https://www.sqlite.org/pragma.html -func (c *Conn) Pragma(str string) []string { - stmt := c.MustPrepare(`PRAGMA ` + str) +func (c *Conn) Pragma(str string) ([]string, error) { + stmt, _, err := c.Prepare(`PRAGMA ` + str) + if err != nil { + return nil, err + } defer stmt.Close() var pragmas []string for stmt.Step() { pragmas = append(pragmas, stmt.ColumnText(0)) } - return pragmas + return pragmas, stmt.Close() } func (c *Conn) error(rc uint64, sql ...string) error { diff --git a/driver/driver.go b/driver/driver.go index b97e30c..a3ee072 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -106,7 +106,7 @@ func (c conn) Begin() (driver.Tx, error) { return c.BeginTx(context.Background(), driver.TxOptions{}) } -func (c conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { +func (c conn) BeginTx(_ context.Context, opts driver.TxOptions) (driver.Tx, error) { switch opts.Isolation { default: return nil, isolationErr @@ -117,9 +117,13 @@ func (c conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, er txBegin := c.txBegin c.txCommit = `COMMIT` if opts.ReadOnly { + query_only, err := c.conn.Pragma("query_only") + if err != nil { + return nil, err + } c.txCommit = ` ROLLBACK; - PRAGMA query_only=` + c.conn.Pragma("query_only")[0] + PRAGMA query_only=` + query_only[0] txBegin = ` BEGIN deferred; PRAGMA query_only=on` diff --git a/error.go b/error.go index 8203f36..4dd3c14 100644 --- a/error.go +++ b/error.go @@ -202,8 +202,6 @@ const ( noFuncErr = errorString("sqlite3: could not find function: ") binaryErr = errorString("sqlite3: no SQLite binary embed/set/loaded") timeErr = errorString("sqlite3: invalid time value") - emptyErr = errorString("sqlite3: empty statement") - tailErr = errorString("sqlite3: non-empty tail") notImplErr = errorString("sqlite3: not implemented") whenceErr = errorString("sqlite3: invalid whence") offsetErr = errorString("sqlite3: invalid offset") diff --git a/example_test.go b/example_test.go index 3753597..c0fa9fa 100644 --- a/example_test.go +++ b/example_test.go @@ -26,7 +26,11 @@ func Example() { log.Fatal(err) } - stmt := db.MustPrepare(`SELECT id, name FROM users`) + stmt, _, err := db.Prepare(`SELECT id, name FROM users`) + if err != nil { + log.Fatal(err) + } + defer stmt.Close() for stmt.Step() { fmt.Println(stmt.ColumnInt(0), stmt.ColumnText(1)) diff --git a/tests/conn_test.go b/tests/conn_test.go index 714d3e0..57ed67b 100644 --- a/tests/conn_test.go +++ b/tests/conn_test.go @@ -202,59 +202,3 @@ func TestConn_Prepare_invalid(t *testing.T) { t.Error("got message:", got) } } - -func TestConn_MustPrepare_empty(t *testing.T) { - t.Parallel() - - db, err := sqlite3.Open(":memory:") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - defer func() { _ = recover() }() - _ = db.MustPrepare(``) - t.Error("want panic") -} - -func TestConn_MustPrepare_tail(t *testing.T) { - t.Parallel() - - db, err := sqlite3.Open(":memory:") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - defer func() { _ = recover() }() - _ = db.MustPrepare(`SELECT 1; -- HERE`) - t.Error("want panic") -} - -func TestConn_MustPrepare_invalid(t *testing.T) { - t.Parallel() - - db, err := sqlite3.Open(":memory:") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - defer func() { _ = recover() }() - _ = db.MustPrepare(`SELECT`) - t.Error("want panic") -} - -func TestConn_Pragma(t *testing.T) { - t.Parallel() - - db, err := sqlite3.Open(":memory:") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - defer func() { _ = recover() }() - _ = db.Pragma("encoding=''") - t.Error("want panic") -}