Enums (result codes, flags…)

This commit is contained in:
Nuno Cruces
2023-01-16 12:54:24 +00:00
parent 1366541e77
commit c480512001
7 changed files with 183 additions and 41 deletions

View File

@@ -4,7 +4,7 @@
This is very much a WIP.
TODO:
Roadmap:
- [x] build SQLite using `zig cc --target=wasm32-wasi`
- [x] `:memory:` databases
- [x] use [`test_demovfs.c`](sqlite3/test_demovfs.c) for file databases
@@ -13,6 +13,7 @@ TODO:
- [`github.com/bvinc/go-sqlite-lite`](https://github.com/bvinc/go-sqlite-lite)
- [`github.com/crawshaw/sqlite`](https://github.com/crawshaw/sqlite)
- [`github.com/zombiezen/go-sqlite`](https://github.com/zombiezen/go-sqlite)
- [`github.com/cvilsmeier/sqinn-go`](https://github.com/cvilsmeier/sqinn-go)
- [`database/sql`](https://pkg.go.dev/database/sql) drivers can come later, if ever
- [ ] implement own VFS to sidestep WASI syscalls:
- locking will be a pain point:
@@ -21,6 +22,14 @@ TODO:
- file access needs to be synchronized, both in-process and out-of-process
- out-of-process should be compatible with SQLite on Windows/Unix
- [ ] benchmark to see if this is usefull at all:
- [`github.com/cvilsmeier/sqinn-go`](https://github.com/cvilsmeier/sqinn-go-bench)
- [`github.com/bvinc/go-sqlite-lite`](https://github.com/bvinc/go-sqlite-lite)
- [`github.com/mattn/go-sqlite3`](https://github.com/mattn/go-sqlite3)
- [`modernc.org/sqlite`](https://modernc.org/sqlite)
Random TODO list:
- wrap more of the SQLite API, enough to run useful queries;
- create a Go VFS that's enough to use `:memory:` databases without WASI;
- expand that VFS to wrap an `io.ReaderAt`;
- optimize small allocations that last a single function call;
- …

View File

@@ -44,6 +44,5 @@ zig cc --target=wasm32-wasi -flto -g0 -O2 \
-Wl,--export=sqlite3_errstr \
-Wl,--export=sqlite3_errmsg \
-Wl,--export=sqlite3_error_offset \
-Wl,--export=sqlite3_extended_errcode \
-Wl,--export=malloc \
-Wl,--export=free

View File

@@ -8,7 +8,7 @@ import (
)
func main() {
db, err := sqlite3.Open(":memory:", 0, "")
db, err := sqlite3.Open(":memory:")
if err != nil {
log.Fatal(err)
}
@@ -23,7 +23,7 @@ func main() {
log.Fatal(err)
}
stmt, _, err := db.Prepare(`SELECT id, name FROM users`, 0)
stmt, _, err := db.Prepare(`SELECT id, name FROM users`)
if err != nil {
log.Fatal(err)
}

49
conn.go
View File

@@ -19,7 +19,11 @@ type Conn struct {
api sqliteAPI
}
func Open(name string, flags uint64, vfs string) (conn *Conn, err error) {
func Open(name string) (conn *Conn, err error) {
return OpenFlags(name, OPEN_READWRITE|OPEN_CREATE)
}
func OpenFlags(name string, flags OpenFlag) (conn *Conn, err error) {
once.Do(compile)
var fs fs.FS
@@ -53,7 +57,6 @@ func Open(name string, flags uint64, vfs string) (conn *Conn, err error) {
errstr: module.ExportedFunction("sqlite3_errstr"),
errmsg: module.ExportedFunction("sqlite3_errmsg"),
erroff: module.ExportedFunction("sqlite3_error_offset"),
errext: module.ExportedFunction("sqlite3_extended_errcode"),
open: module.ExportedFunction("sqlite3_open_v2"),
close: module.ExportedFunction("sqlite3_close"),
prepare: module.ExportedFunction("sqlite3_prepare_v3"),
@@ -75,16 +78,7 @@ func Open(name string, flags uint64, vfs string) (conn *Conn, err error) {
namePtr := c.newString(name)
connPtr := c.newBytes(ptrSize)
if flags == 0 {
flags = OPEN_READWRITE | OPEN_CREATE
}
var vfsPtr uint32
if vfs != "" {
vfsPtr = c.newString(vfs)
}
r, err := c.api.open.Call(ctx, uint64(namePtr), uint64(connPtr), flags, uint64(vfsPtr))
r, err := c.api.open.Call(ctx, uint64(namePtr), uint64(connPtr), uint64(flags), 0)
if err != nil {
return nil, err
}
@@ -92,9 +86,8 @@ func Open(name string, flags uint64, vfs string) (conn *Conn, err error) {
c.handle, _ = c.memory.ReadUint32Le(connPtr)
c.free(connPtr)
c.free(namePtr)
c.free(vfsPtr)
if r[0] != OK {
if r[0] != _OK {
return nil, c.error(r[0])
}
return &c, nil
@@ -106,7 +99,7 @@ func (c *Conn) Close() error {
return err
}
if r[0] != OK {
if r[0] != _OK {
return c.error(r[0])
}
return c.module.Close(context.TODO())
@@ -122,19 +115,23 @@ func (c *Conn) Exec(sql string) error {
c.free(sqlPtr)
if r[0] != OK {
if r[0] != _OK {
return c.error(r[0])
}
return nil
}
func (c *Conn) Prepare(sql string, flags uint64, args ...any) (stmt *Stmt, tail string, err error) {
func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) {
return c.PrepareFlags(sql, 0)
}
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) {
sqlPtr := c.newString(sql)
stmtPtr := c.newBytes(ptrSize)
tailPtr := c.newBytes(ptrSize)
r, err := c.api.prepare.Call(context.TODO(), uint64(c.handle),
uint64(sqlPtr), uint64(len(sql)+1), flags,
uint64(sqlPtr), uint64(len(sql)+1), uint64(flags),
uint64(stmtPtr), uint64(tailPtr))
if err != nil {
return nil, "", err
@@ -149,7 +146,7 @@ func (c *Conn) Prepare(sql string, flags uint64, args ...any) (stmt *Stmt, tail
c.free(stmtPtr)
c.free(sqlPtr)
if r[0] != OK {
if r[0] != _OK {
return nil, "", c.error(r[0])
}
if stmt.handle == 0 {
@@ -159,12 +156,15 @@ func (c *Conn) Prepare(sql string, flags uint64, args ...any) (stmt *Stmt, tail
}
func (c *Conn) error(rc uint64) *Error {
serr := Error{Code: int(rc)}
serr := Error{
Code: ErrorCode(rc & 0xFF),
ExtendedCode: ExtendedErrorCode(rc),
}
var r []uint64
// string
r, _ = c.api.errstr.Call(context.TODO(), uint64(rc))
r, _ = c.api.errstr.Call(context.TODO(), rc)
if r != nil {
serr.str = c.getString(uint32(r[0]), 512)
}
@@ -175,12 +175,6 @@ func (c *Conn) error(rc uint64) *Error {
serr.msg = c.getString(uint32(r[0]), 512)
}
// extended code
r, _ = c.api.errext.Call(context.TODO(), uint64(c.handle))
if r != nil {
serr.ExtendedCode = int(r[0])
}
if serr.str == serr.msg {
serr.msg = ""
}
@@ -247,7 +241,6 @@ type sqliteAPI struct {
free api.Function
errstr api.Function
errmsg api.Function
errext api.Function
erroff api.Function
open api.Function
close api.Function

151
const.go
View File

@@ -1,12 +1,153 @@
package sqlite3
const (
OK = 0
ROW = 100
DONE = 101
_OK = 0 /* Successful result */
_ROW = 100 /* sqlite3_step() has another row ready */
_DONE = 101 /* sqlite3_step() has finished executing */
)
type ErrorCode int
const (
OPEN_READWRITE = 0x00000002
OPEN_CREATE = 0x00000004
ERROR ErrorCode = 1 /* Generic error */
INTERNAL ErrorCode = 2 /* Internal logic error in SQLite */
PERM ErrorCode = 3 /* Access permission denied */
ABORT ErrorCode = 4 /* Callback routine requested an abort */
BUSY ErrorCode = 5 /* The database file is locked */
LOCKED ErrorCode = 6 /* A table in the database is locked */
NOMEM ErrorCode = 7 /* A malloc() failed */
READONLY ErrorCode = 8 /* Attempt to write a readonly database */
INTERRUPT ErrorCode = 9 /* Operation terminated by sqlite3_interrupt()*/
IOERR ErrorCode = 10 /* Some kind of disk I/O error occurred */
CORRUPT ErrorCode = 11 /* The database disk image is malformed */
NOTFOUND ErrorCode = 12 /* Unknown opcode in sqlite3_file_control() */
FULL ErrorCode = 13 /* Insertion failed because database is full */
CANTOPEN ErrorCode = 14 /* Unable to open the database file */
PROTOCOL ErrorCode = 15 /* Database lock protocol error */
EMPTY ErrorCode = 16 /* Internal use only */
SCHEMA ErrorCode = 17 /* The database schema changed */
TOOBIG ErrorCode = 18 /* String or BLOB exceeds size limit */
CONSTRAINT ErrorCode = 19 /* Abort due to constraint violation */
MISMATCH ErrorCode = 20 /* Data type mismatch */
MISUSE ErrorCode = 21 /* Library used incorrectly */
NOLFS ErrorCode = 22 /* Uses OS features not supported on host */
AUTH ErrorCode = 23 /* Authorization denied */
FORMAT ErrorCode = 24 /* Not used */
RANGE ErrorCode = 25 /* 2nd parameter to sqlite3_bind out of range */
NOTADB ErrorCode = 26 /* File opened that is not a database file */
NOTICE ErrorCode = 27 /* Notifications from sqlite3_log() */
WARNING ErrorCode = 28 /* Warnings from sqlite3_log() */
)
type ExtendedErrorCode int
const (
ERROR_MISSING_COLLSEQ = ExtendedErrorCode(ERROR | (1 << 8))
ERROR_RETRY = ExtendedErrorCode(ERROR | (2 << 8))
ERROR_SNAPSHOT = ExtendedErrorCode(ERROR | (3 << 8))
IOERR_READ = ExtendedErrorCode(IOERR | (1 << 8))
IOERR_SHORT_READ = ExtendedErrorCode(IOERR | (2 << 8))
IOERR_WRITE = ExtendedErrorCode(IOERR | (3 << 8))
IOERR_FSYNC = ExtendedErrorCode(IOERR | (4 << 8))
IOERR_DIR_FSYNC = ExtendedErrorCode(IOERR | (5 << 8))
IOERR_TRUNCATE = ExtendedErrorCode(IOERR | (6 << 8))
IOERR_FSTAT = ExtendedErrorCode(IOERR | (7 << 8))
IOERR_UNLOCK = ExtendedErrorCode(IOERR | (8 << 8))
IOERR_RDLOCK = ExtendedErrorCode(IOERR | (9 << 8))
IOERR_DELETE = ExtendedErrorCode(IOERR | (10 << 8))
IOERR_BLOCKED = ExtendedErrorCode(IOERR | (11 << 8))
IOERR_NOMEM = ExtendedErrorCode(IOERR | (12 << 8))
IOERR_ACCESS = ExtendedErrorCode(IOERR | (13 << 8))
IOERR_CHECKRESERVEDLOCK = ExtendedErrorCode(IOERR | (14 << 8))
IOERR_LOCK = ExtendedErrorCode(IOERR | (15 << 8))
IOERR_CLOSE = ExtendedErrorCode(IOERR | (16 << 8))
IOERR_DIR_CLOSE = ExtendedErrorCode(IOERR | (17 << 8))
IOERR_SHMOPEN = ExtendedErrorCode(IOERR | (18 << 8))
IOERR_SHMSIZE = ExtendedErrorCode(IOERR | (19 << 8))
IOERR_SHMLOCK = ExtendedErrorCode(IOERR | (20 << 8))
IOERR_SHMMAP = ExtendedErrorCode(IOERR | (21 << 8))
IOERR_SEEK = ExtendedErrorCode(IOERR | (22 << 8))
IOERR_DELETE_NOENT = ExtendedErrorCode(IOERR | (23 << 8))
IOERR_MMAP = ExtendedErrorCode(IOERR | (24 << 8))
IOERR_GETTEMPPATH = ExtendedErrorCode(IOERR | (25 << 8))
IOERR_CONVPATH = ExtendedErrorCode(IOERR | (26 << 8))
IOERR_VNODE = ExtendedErrorCode(IOERR | (27 << 8))
IOERR_AUTH = ExtendedErrorCode(IOERR | (28 << 8))
IOERR_BEGIN_ATOMIC = ExtendedErrorCode(IOERR | (29 << 8))
IOERR_COMMIT_ATOMIC = ExtendedErrorCode(IOERR | (30 << 8))
IOERR_ROLLBACK_ATOMIC = ExtendedErrorCode(IOERR | (31 << 8))
IOERR_DATA = ExtendedErrorCode(IOERR | (32 << 8))
IOERR_CORRUPTFS = ExtendedErrorCode(IOERR | (33 << 8))
LOCKED_SHAREDCACHE = ExtendedErrorCode(LOCKED | (1 << 8))
LOCKED_VTAB = ExtendedErrorCode(LOCKED | (2 << 8))
BUSY_RECOVERY = ExtendedErrorCode(BUSY | (1 << 8))
BUSY_SNAPSHOT = ExtendedErrorCode(BUSY | (2 << 8))
BUSY_TIMEOUT = ExtendedErrorCode(BUSY | (3 << 8))
CANTOPEN_NOTEMPDIR = ExtendedErrorCode(CANTOPEN | (1 << 8))
CANTOPEN_ISDIR = ExtendedErrorCode(CANTOPEN | (2 << 8))
CANTOPEN_FULLPATH = ExtendedErrorCode(CANTOPEN | (3 << 8))
CANTOPEN_CONVPATH = ExtendedErrorCode(CANTOPEN | (4 << 8))
CANTOPEN_DIRTYWAL = ExtendedErrorCode(CANTOPEN | (5 << 8)) /* Not Used */
CANTOPEN_SYMLINK = ExtendedErrorCode(CANTOPEN | (6 << 8))
CORRUPT_VTAB = ExtendedErrorCode(CORRUPT | (1 << 8))
CORRUPT_SEQUENCE = ExtendedErrorCode(CORRUPT | (2 << 8))
CORRUPT_INDEX = ExtendedErrorCode(CORRUPT | (3 << 8))
READONLY_RECOVERY = ExtendedErrorCode(READONLY | (1 << 8))
READONLY_CANTLOCK = ExtendedErrorCode(READONLY | (2 << 8))
READONLY_ROLLBACK = ExtendedErrorCode(READONLY | (3 << 8))
READONLY_DBMOVED = ExtendedErrorCode(READONLY | (4 << 8))
READONLY_CANTINIT = ExtendedErrorCode(READONLY | (5 << 8))
READONLY_DIRECTORY = ExtendedErrorCode(READONLY | (6 << 8))
ABORT_ROLLBACK = ExtendedErrorCode(ABORT | (2 << 8))
CONSTRAINT_CHECK = ExtendedErrorCode(CONSTRAINT | (1 << 8))
CONSTRAINT_COMMITHOOK = ExtendedErrorCode(CONSTRAINT | (2 << 8))
CONSTRAINT_FOREIGNKEY = ExtendedErrorCode(CONSTRAINT | (3 << 8))
CONSTRAINT_FUNCTION = ExtendedErrorCode(CONSTRAINT | (4 << 8))
CONSTRAINT_NOTNULL = ExtendedErrorCode(CONSTRAINT | (5 << 8))
CONSTRAINT_PRIMARYKEY = ExtendedErrorCode(CONSTRAINT | (6 << 8))
CONSTRAINT_TRIGGER = ExtendedErrorCode(CONSTRAINT | (7 << 8))
CONSTRAINT_UNIQUE = ExtendedErrorCode(CONSTRAINT | (8 << 8))
CONSTRAINT_VTAB = ExtendedErrorCode(CONSTRAINT | (9 << 8))
CONSTRAINT_ROWID = ExtendedErrorCode(CONSTRAINT | (10 << 8))
CONSTRAINT_PINNED = ExtendedErrorCode(CONSTRAINT | (11 << 8))
CONSTRAINT_DATATYPE = ExtendedErrorCode(CONSTRAINT | (12 << 8))
NOTICE_RECOVER_WAL = ExtendedErrorCode(NOTICE | (1 << 8))
NOTICE_RECOVER_ROLLBACK = ExtendedErrorCode(NOTICE | (2 << 8))
WARNING_AUTOINDEX = ExtendedErrorCode(WARNING | (1 << 8))
AUTH_USER = ExtendedErrorCode(AUTH | (1 << 8))
)
type OpenFlag uint
const (
OPEN_READONLY OpenFlag = 0x00000001 /* Ok for sqlite3_open_v2() */
OPEN_READWRITE OpenFlag = 0x00000002 /* Ok for sqlite3_open_v2() */
OPEN_CREATE OpenFlag = 0x00000004 /* Ok for sqlite3_open_v2() */
OPEN_DELETEONCLOSE OpenFlag = 0x00000008 /* VFS only */
OPEN_EXCLUSIVE OpenFlag = 0x00000010 /* VFS only */
OPEN_AUTOPROXY OpenFlag = 0x00000020 /* VFS only */
OPEN_URI OpenFlag = 0x00000040 /* Ok for sqlite3_open_v2() */
OPEN_MEMORY OpenFlag = 0x00000080 /* Ok for sqlite3_open_v2() */
OPEN_MAIN_DB OpenFlag = 0x00000100 /* VFS only */
OPEN_TEMP_DB OpenFlag = 0x00000200 /* VFS only */
OPEN_TRANSIENT_DB OpenFlag = 0x00000400 /* VFS only */
OPEN_MAIN_JOURNAL OpenFlag = 0x00000800 /* VFS only */
OPEN_TEMP_JOURNAL OpenFlag = 0x00001000 /* VFS only */
OPEN_SUBJOURNAL OpenFlag = 0x00002000 /* VFS only */
OPEN_SUPER_JOURNAL OpenFlag = 0x00004000 /* VFS only */
OPEN_NOMUTEX OpenFlag = 0x00008000 /* Ok for sqlite3_open_v2() */
OPEN_FULLMUTEX OpenFlag = 0x00010000 /* Ok for sqlite3_open_v2() */
OPEN_SHAREDCACHE OpenFlag = 0x00020000 /* Ok for sqlite3_open_v2() */
OPEN_PRIVATECACHE OpenFlag = 0x00040000 /* Ok for sqlite3_open_v2() */
OPEN_WAL OpenFlag = 0x00080000 /* VFS only */
OPEN_NOFOLLOW OpenFlag = 0x01000000 /* Ok for sqlite3_open_v2() */
OPEN_EXRESCODE OpenFlag = 0x02000000 /* Extended result codes */
)
type PrepareFlag uint
const (
PREPARE_PERSISTENT PrepareFlag = 0x01
PREPARE_NORMALIZE PrepareFlag = 0x02
PREPARE_NO_VTAB PrepareFlag = 0x04
)

View File

@@ -6,8 +6,8 @@ import (
)
type Error struct {
Code int
ExtendedCode int
Code ErrorCode
ExtendedCode ExtendedErrorCode
str string
msg string
}
@@ -19,7 +19,7 @@ func (e Error) Error() string {
if e.str != "" {
b.WriteString(e.str)
} else {
b.WriteString(strconv.Itoa(e.Code))
b.WriteString(strconv.Itoa(int(e.Code)))
}
if e.msg != "" {

View File

@@ -14,7 +14,7 @@ func (s *Stmt) Close() error {
}
s.handle = 0
if r[0] != OK {
if r[0] != _OK {
return s.c.error(r[0])
}
return nil