From c7165a2e5696065daa7535b054e305f923e0ffdf Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Wed, 1 Mar 2023 10:34:08 +0000 Subject: [PATCH] Documentation. --- blob.go | 4 +++- compile.go | 9 +++++++-- conn.go | 20 +++++++++++++++----- driver_test.go | 16 +++++++++------- error.go | 3 ++- example_test.go | 5 +---- stmt.go | 2 +- tests/conn_test.go | 8 ++------ time.go | 2 +- tx.go | 10 ++++++++-- 10 files changed, 49 insertions(+), 30 deletions(-) diff --git a/blob.go b/blob.go index 2ff84d8..742b833 100644 --- a/blob.go +++ b/blob.go @@ -9,6 +9,8 @@ type ZeroBlob int64 // Blob is a handle to an open BLOB. // +// It implements [io.ReadWriteSeeker] for incremental BLOB I/O. +// // https://www.sqlite.org/c3ref/blob.html type Blob struct { c *Conn @@ -50,7 +52,7 @@ func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, // Close closes a BLOB handle. // -// It is safe to close a nil, zero or closed BLOB handle. +// It is safe to close a nil, zero or closed Blob. // // https://www.sqlite.org/c3ref/blob_close.html func (b *Blob) Close() error { diff --git a/compile.go b/compile.go index 45991c7..e454625 100644 --- a/compile.go +++ b/compile.go @@ -13,9 +13,14 @@ import ( "github.com/tetratelabs/wazero/api" ) -// Configure SQLite. +// Configure SQLite WASM. +// +// Importing package embed initializes these +// with an appropriate build of SQLite: +// +// import _ "github.com/ncruces/go-sqlite3/embed" var ( - Binary []byte // Binary to load. + Binary []byte // WASM binary to load. Path string // Path to load the binary from. ) diff --git a/conn.go b/conn.go index cf0d1aa..8f5f0bb 100644 --- a/conn.go +++ b/conn.go @@ -13,6 +13,7 @@ import ( ) // Conn is a database connection handle. +// A Conn is not safe for concurrent use by multiple goroutines. // // https://www.sqlite.org/c3ref/sqlite3.html type Conn struct { @@ -92,7 +93,7 @@ func OpenFlags(filename string, flags OpenFlag) (conn *Conn, err error) { // open blob handles, and/or unfinished backup objects, // Close will leave the database connection open and return [BUSY]. // -// It is safe to close a nil, zero or closed connection. +// It is safe to close a nil, zero or closed Conn. // // https://www.sqlite.org/c3ref/close.html func (c *Conn) Close() error { @@ -125,12 +126,15 @@ func (c *Conn) Exec(sql string) error { } // MustPrepare calls [Conn.Prepare] and panics on error, -// or a non empty tail. +// 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) { panic(tailErr) } @@ -208,7 +212,7 @@ func (c *Conn) Changes() int64 { // Subsequent uses of the connection will return [INTERRUPT] // until the context is reset by another call to SetInterrupt. // -// For example, a timeout can be associated with a connection: +// To associate a timeout with a connection: // // ctx, cancel := context.WithTimeout(context.TODO(), 100*time.Millisecond) // conn.SetInterrupt(ctx) @@ -287,7 +291,7 @@ func (c *Conn) sendInterrupt() { c.call(c.api.interrupt, uint64(c.handle)) } -// Pragma executes a PRAGMA statement and returns any result as a string. +// Pragma executes a PRAGMA statement and returns any results. // // https://www.sqlite.org/pragma.html func (c *Conn) Pragma(str string) []string { @@ -430,7 +434,13 @@ func (a *arena) string(s string) uint32 { return ptr } -// DriverConn is implemented by the SQLite database/sql driver connection. +// DriverConn is implemented by the SQLite [database/sql] driver connection. +// +// It can be used to access advanced SQLite features like +// [savepoints] and [incremental BLOB I/O]. +// +// [savepoints]: https://www.sqlite.org/lang_savepoint.html +// [incremental BLOB I/O]: https://www.sqlite.org/c3ref/blob_open.html type DriverConn interface { driver.ConnBeginTx driver.ExecerContext diff --git a/driver_test.go b/driver_test.go index 5c10fc4..e09f58d 100644 --- a/driver_test.go +++ b/driver_test.go @@ -5,23 +5,25 @@ import ( "database/sql" "fmt" "log" + "os" "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/driver" _ "github.com/ncruces/go-sqlite3/embed" ) -const demo = "demo.db" +var db *sql.DB func ExampleDriverConn() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - db, err := sql.Open("sqlite3", demo) + var err error + db, err = sql.Open("sqlite3", "demo.db") if err != nil { log.Fatal(err) } defer db.Close() + defer os.Remove("demo.db") + + ctx := context.Background() conn, err := db.Conn(ctx) if err != nil { @@ -34,12 +36,12 @@ func ExampleDriverConn() { log.Fatal(err) } - r, err := conn.ExecContext(ctx, `INSERT INTO test VALUES (?)`, sqlite3.ZeroBlob(11)) + res, err := conn.ExecContext(ctx, `INSERT INTO test VALUES (?)`, sqlite3.ZeroBlob(11)) if err != nil { log.Fatal(err) } - id, err := r.LastInsertId() + id, err := res.LastInsertId() if err != nil { log.Fatal(err) } diff --git a/error.go b/error.go index d3a1cbd..ab5a7d6 100644 --- a/error.go +++ b/error.go @@ -52,7 +52,7 @@ func (e *Error) Error() string { // Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode]. // -// This makes it possible to do: +// It makes it possible to do: // // if errors.Is(err, sqlite3.BUSY) { // // ... handle BUSY @@ -201,6 +201,7 @@ 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") diff --git a/example_test.go b/example_test.go index 6101fcf..3753597 100644 --- a/example_test.go +++ b/example_test.go @@ -26,10 +26,7 @@ func Example() { log.Fatal(err) } - stmt, _, err := db.Prepare(`SELECT id, name FROM users`) - if err != nil { - log.Fatal(err) - } + stmt := db.MustPrepare(`SELECT id, name FROM users`) for stmt.Step() { fmt.Println(stmt.ColumnInt(0), stmt.ColumnText(1)) diff --git a/stmt.go b/stmt.go index 76813bc..1fa0fad 100644 --- a/stmt.go +++ b/stmt.go @@ -16,7 +16,7 @@ type Stmt struct { // Close destroys the prepared statement object. // -// It is safe to close a nil, zero or closed prepared statement. +// It is safe to close a nil, zero or closed Stmt. // // https://www.sqlite.org/c3ref/finalize.html func (s *Stmt) Close() error { diff --git a/tests/conn_test.go b/tests/conn_test.go index feb0534..714d3e0 100644 --- a/tests/conn_test.go +++ b/tests/conn_test.go @@ -213,12 +213,8 @@ func TestConn_MustPrepare_empty(t *testing.T) { defer db.Close() defer func() { _ = recover() }() - stmt := db.MustPrepare(``) - defer stmt.Close() - - if stmt != nil { - t.Error("want nil") - } + _ = db.MustPrepare(``) + t.Error("want panic") } func TestConn_MustPrepare_tail(t *testing.T) { diff --git a/time.go b/time.go index 2fc8c98..a1308cf 100644 --- a/time.go +++ b/time.go @@ -68,7 +68,7 @@ const ( // // Time values encoded with [time.RFC3339Nano] cannot be sorted as strings // to produce a time-ordered sequence. -// Use [TimeFormat7TZ] for time-ordered encoding. +// Use [TimeFormat7] for time-ordered encoding. // // Formats [TimeFormat1] through [TimeFormat10] // convert time values to UTC before encoding. diff --git a/tx.go b/tx.go index aeb2887..8d33096 100644 --- a/tx.go +++ b/tx.go @@ -44,7 +44,7 @@ func (c *Conn) BeginExclusive() (Tx, error) { return Tx{c}, nil } -// End calls either [Commit] or [Rollback] +// End calls either [Tx.Commit] or [Tx.Rollback] // depending on whether *error points to a nil or non-nil error. // // This is meant to be deferred: @@ -56,7 +56,7 @@ func (c *Conn) BeginExclusive() (Tx, error) { // // ... do work in the transaction // } // -// https://www.sqlite.org/lang_savepoint.html +// https://www.sqlite.org/lang_transaction.html func (tx Tx) End(errp *error) { recovered := recover() if recovered != nil { @@ -84,10 +84,16 @@ func (tx Tx) End(errp *error) { } } +// Commit commits the transaction. +// +// https://www.sqlite.org/lang_transaction.html func (tx Tx) Commit() error { return tx.c.Exec(`COMMIT`) } +// Rollback rollsback the transaction. +// +// https://www.sqlite.org/lang_transaction.html func (tx Tx) Rollback() error { // ROLLBACK even if the connection has been interrupted. old := tx.c.SetInterrupt(context.Background())