From ec5bd236f8b4036e5a3ddd6ce0768052917f617e Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Sat, 18 Feb 2023 03:43:17 +0000 Subject: [PATCH] Documentation. --- README.md | 9 +++++---- api.go | 1 + conn.go | 9 +++++++++ const.go | 23 +++++++++++++++++++---- driver/example_test.go | 22 +++++++++++----------- example/main.go => example_test.go | 13 ++++++++++--- vfs.go | 6 +++--- vfs_test.go | 4 ++-- 8 files changed, 60 insertions(+), 27 deletions(-) rename example/main.go => example_test.go (83%) diff --git a/README.md b/README.md index 3bca6e9..bb82da9 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ ⚠️ CAUTION ⚠️ -This is still very much a WIP.\ -DO NOT USE this with data you care about. +This is a WIP.\ +DO NOT USE with data you care about. Roadmap: - [x] build SQLite using `zig cc --target=wasm32-wasi` @@ -15,6 +15,7 @@ Roadmap: - [x] port [`test_demovfs.c`](https://www.sqlite.org/src/doc/trunk/src/test_demovfs.c) to Go - branch [`wasi`](https://github.com/ncruces/go-sqlite3/tree/wasi) uses `test_demovfs.c` directly - [x] design a simple, nice API, enough for simple use cases -- [x] minimal `database/sql` driver +- [x] provide a simple `database/sql` driver - [x] file locking, compatible with SQLite on Windows/Unix -- [ ] shared memory, compatible with SQLite on Windows/Unix \ No newline at end of file +- [ ] shared memory, compatible with SQLite on Windows/Unix + - needed for improved WAL mode \ No newline at end of file diff --git a/api.go b/api.go index 76f91bf..698cda1 100644 --- a/api.go +++ b/api.go @@ -1,3 +1,4 @@ +// Package sqlite3 wraps the C SQLite API. package sqlite3 import ( diff --git a/conn.go b/conn.go index 774506b..18fcb61 100644 --- a/conn.go +++ b/conn.go @@ -205,6 +205,10 @@ func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail str return } +// LastInsertRowID returns the rowid of the most recent successful INSERT +// on the database connection. +// +// https://www.sqlite.org/c3ref/last_insert_rowid.html func (c *Conn) LastInsertRowID() uint64 { r, err := c.api.lastRowid.Call(c.ctx, uint64(c.handle)) if err != nil { @@ -213,6 +217,11 @@ func (c *Conn) LastInsertRowID() uint64 { return r[0] } +// Changes returns the number of rows modified, inserted or deleted +// by the most recently completed INSERT, UPDATE or DELETE statement +// on the database connection. +// +// https://www.sqlite.org/c3ref/changes.html func (c *Conn) Changes() uint64 { r, err := c.api.changes.Call(c.ctx, uint64(c.handle)) if err != nil { diff --git a/const.go b/const.go index e79da4f..9ba7553 100644 --- a/const.go +++ b/const.go @@ -15,6 +15,9 @@ const ( ptrlen = 4 ) +// ErrorCode is a result code that [Error.Code] might return. +// +// https://www.sqlite.org/rescode.html type ErrorCode uint8 const ( @@ -48,6 +51,9 @@ const ( WARNING ErrorCode = 28 /* Warnings from sqlite3_log() */ ) +// ExtendedErrorCode is a result code that [Error.ExtendedCode] might return. +// +// https://www.sqlite.org/rescode.html type ( ExtendedErrorCode uint16 xErrorCode = ExtendedErrorCode @@ -129,6 +135,9 @@ const ( AUTH_USER ExtendedErrorCode = xErrorCode(AUTH) | (1 << 8) ) +// OpenFlag is a flag for a file open operation. +// +// https://www.sqlite.org/c3ref/c_open_autoproxy.html type OpenFlag uint32 const ( @@ -156,14 +165,17 @@ const ( OPEN_EXRESCODE OpenFlag = 0x02000000 /* Extended result codes */ ) -type AccessFlag uint32 +type _AccessFlag uint32 const ( - ACCESS_EXISTS AccessFlag = 0 - ACCESS_READWRITE AccessFlag = 1 /* Used by PRAGMA temp_store_directory */ - ACCESS_READ AccessFlag = 2 /* Unused */ + _ACCESS_EXISTS _AccessFlag = 0 + _ACCESS_READWRITE _AccessFlag = 1 /* Used by PRAGMA temp_store_directory */ + _ACCESS_READ _AccessFlag = 2 /* Unused */ ) +// PrepareFlag is a flag that can be passed to [Conn.PrepareFlags]. +// +// https://www.sqlite.org/c3ref/c_prepare_normalize.html type PrepareFlag uint32 const ( @@ -172,6 +184,9 @@ const ( PREPARE_NO_VTAB PrepareFlag = 0x04 ) +// Datatype is a fundamental datatype of SQLite. +// +// https://www.sqlite.org/c3ref/c_blob.html type Datatype uint32 const ( diff --git a/driver/example_test.go b/driver/example_test.go index 749db76..f5df3f4 100644 --- a/driver/example_test.go +++ b/driver/example_test.go @@ -1,5 +1,7 @@ package driver_test +// Adapted from: https://go.dev/doc/tutorial/database-access + import ( "database/sql" "fmt" @@ -12,9 +14,14 @@ import ( var db *sql.DB -func Example() { - // Adapted from: https://go.dev/doc/tutorial/database-access +type Album struct { + ID int64 + Title string + Artist string + Price float32 +} +func Example() { // Get a database handle. var err error db, err = sql.Open("sqlite3", "./recordings.db") @@ -24,7 +31,7 @@ func Example() { defer db.Close() defer os.Remove("./recordings.db") - err = setupDatabase() + err = createAlbumsTable() if err != nil { log.Fatal(err) } @@ -58,14 +65,7 @@ func Example() { // ID of added album: 5 } -type Album struct { - ID int64 - Title string - Artist string - Price float32 -} - -func setupDatabase() error { +func createAlbumsTable() error { _, err := db.Exec(` DROP TABLE IF EXISTS album; CREATE TABLE album ( diff --git a/example/main.go b/example_test.go similarity index 83% rename from example/main.go rename to example_test.go index 2d04bf5..69c461f 100644 --- a/example/main.go +++ b/example_test.go @@ -1,4 +1,4 @@ -package main +package sqlite3_test import ( "fmt" @@ -8,8 +8,10 @@ import ( _ "github.com/ncruces/go-sqlite3/embed" ) -func main() { - db, err := sqlite3.Open(":memory:") +const memory = ":memory:" + +func Example() { + db, err := sqlite3.Open(memory) if err != nil { log.Fatal(err) } @@ -45,4 +47,9 @@ func main() { if err != nil { log.Fatal(err) } + + // Output: + // 0 go + // 1 zig + // 2 whatever } diff --git a/vfs.go b/vfs.go index 311a973..6b4826b 100644 --- a/vfs.go +++ b/vfs.go @@ -148,7 +148,7 @@ func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32) return _OK } -func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags AccessFlag, pResOut uint32) uint32 { +func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags _AccessFlag, pResOut uint32) uint32 { // Consider using [syscall.Access] for [ACCESS_READWRITE]/[ACCESS_READ] // (as the Unix VFS does). @@ -157,7 +157,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags Ac var res uint32 switch { - case flags == ACCESS_EXISTS: + case flags == _ACCESS_EXISTS: switch { case err == nil: res = 1 @@ -169,7 +169,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags Ac case err == nil: var want fs.FileMode = syscall.S_IRUSR - if flags == ACCESS_READWRITE { + if flags == _ACCESS_READWRITE { want |= syscall.S_IWUSR } if fi.IsDir() { diff --git a/vfs_test.go b/vfs_test.go index 4b7df92..6af6d21 100644 --- a/vfs_test.go +++ b/vfs_test.go @@ -166,7 +166,7 @@ func Test_vfsAccess(t *testing.T) { mem := newMemory(128 + _MAX_PATHNAME) mem.writeString(8, t.TempDir()) - rc := vfsAccess(context.TODO(), mem.mod, 0, 8, ACCESS_EXISTS, 4) + rc := vfsAccess(context.TODO(), mem.mod, 0, 8, _ACCESS_EXISTS, 4) if rc != _OK { t.Fatal("returned", rc) } @@ -174,7 +174,7 @@ func Test_vfsAccess(t *testing.T) { t.Error("directory did not exist") } - rc = vfsAccess(context.TODO(), mem.mod, 0, 8, ACCESS_READWRITE, 4) + rc = vfsAccess(context.TODO(), mem.mod, 0, 8, _ACCESS_READWRITE, 4) if rc != _OK { t.Fatal("returned", rc) }