diff --git a/bench/wasm_test.go b/bench/wasm_test.go index 28de90c..9f33f40 100644 --- a/bench/wasm_test.go +++ b/bench/wasm_test.go @@ -68,12 +68,7 @@ func wasmTest() { } defer stmt.Close() - for { - if row, err := stmt.Step(); err != nil { - panic(err) - } else if !row { - break - } + for stmt.Step() { id := stmt.ColumnInt(0) name := stmt.ColumnText(1) age := stmt.ColumnInt64(2) @@ -82,5 +77,8 @@ func wasmTest() { panic("wrong row values") } } + if stmt.Err() != nil { + panic(err) + } }() } diff --git a/cmd/main.go b/cmd/main.go index 2476513..9f7d130 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -29,14 +29,12 @@ func main() { log.Fatal(err) } - for { - if row, err := stmt.Step(); err != nil { - log.Fatal(err) - } else if !row { - break - } + for stmt.Step() { fmt.Println(stmt.ColumnInt(0), stmt.ColumnText(1)) } + if stmt.Err() != nil { + log.Fatal(err) + } err = stmt.Close() if err != nil { diff --git a/conn.go b/conn.go index 203e6e0..3413a23 100644 --- a/conn.go +++ b/conn.go @@ -142,7 +142,7 @@ func (c *Conn) error(rc uint64) error { } serr := Error{ - Code: ErrorCode(rc & 0xFF), + Code: ErrorCode(rc), ExtendedCode: ExtendedErrorCode(rc), } diff --git a/const.go b/const.go index ee5a564..92ef051 100644 --- a/const.go +++ b/const.go @@ -10,7 +10,7 @@ const ( _MAX_PATHNAME = 512 ) -type ErrorCode int +type ErrorCode uint8 const ( ERROR ErrorCode = 1 /* Generic error */ @@ -21,7 +21,7 @@ const ( 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()*/ + 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() */ @@ -43,82 +43,82 @@ const ( WARNING ErrorCode = 28 /* Warnings from sqlite3_log() */ ) -type ExtendedErrorCode int +type ExtendedErrorCode uint16 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)) + 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 diff --git a/build_deps.sh b/embed/build.sh similarity index 82% rename from build_deps.sh rename to embed/build.sh index cde2d01..3746268 100755 --- a/build_deps.sh +++ b/embed/build.sh @@ -4,18 +4,11 @@ set -eo pipefail cd -P -- "$(dirname -- "$0")" # download SQLite -if [ ! -f "sqlite3/sqlite3.c" ]; then - url="https://www.sqlite.org/2022/sqlite-amalgamation-3400100.zip" - curl "$url" > sqlite3/sqlite.zip - unzip -d sqlite3/ sqlite3/sqlite.zip - mv sqlite3/sqlite-amalgamation-*/sqlite3* sqlite3/ - rm -rf sqlite3/sqlite-amalgamation-* - rm sqlite3/sqlite.zip -fi +../sqlite3/download.sh # build SQLite zig cc --target=wasm32-wasi -flto -g0 -O2 \ - -o embed/sqlite3.wasm sqlite3/*.c \ + -o sqlite3.wasm ../sqlite3/*.c \ -mmutable-globals \ -mbulk-memory -mreference-types \ -mnontrapping-fptoint -msign-ext \ @@ -27,15 +20,18 @@ zig cc --target=wasm32-wasi -flto -g0 -O2 \ -DSQLITE_DEFAULT_LOCKING_MODE=1 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ + -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_AUTOINIT \ -DSQLITE_OMIT_UTF16 \ + -DSQLITE_USE_ALLOCA \ -Wl,--export=malloc \ -Wl,--export=free \ -Wl,--export=malloc_destructor \ + -Wl,--export=sqlite3_errcode \ -Wl,--export=sqlite3_errstr \ -Wl,--export=sqlite3_errmsg \ -Wl,--export=sqlite3_error_offset \ diff --git a/error.go b/error.go index 3461017..941925f 100644 --- a/error.go +++ b/error.go @@ -12,7 +12,7 @@ type Error struct { msg string } -func (e Error) Error() string { +func (e *Error) Error() string { var b strings.Builder b.WriteString("sqlite3: ") diff --git a/sqlite3/download.sh b/sqlite3/download.sh new file mode 100755 index 0000000..84995d1 --- /dev/null +++ b/sqlite3/download.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eo pipefail + +cd -P -- "$(dirname -- "$0")" + +if [ ! -f "sqlite3.c" ]; then + url="https://www.sqlite.org/2022/sqlite-amalgamation-3400100.zip" + curl "$url" > sqlite.zip + unzip -d . sqlite.zip + mv sqlite-amalgamation-*/sqlite3* . + rm -rf sqlite-amalgamation-* + rm sqlite.zip +fi \ No newline at end of file diff --git a/stmt.go b/stmt.go index 0df44b2..c683b21 100644 --- a/stmt.go +++ b/stmt.go @@ -7,6 +7,7 @@ import ( type Stmt struct { c *Conn handle uint32 + err error } func (s *Stmt) Close() error { @@ -27,18 +28,25 @@ func (s *Stmt) Reset() error { return s.c.error(r[0]) } -func (s *Stmt) Step() (row bool, err error) { +func (s *Stmt) Step() bool { r, err := s.c.api.step.Call(s.c.ctx, uint64(s.handle)) if err != nil { - return false, err + s.err = err + return false } if r[0] == _ROW { - return true, nil + return true } if r[0] == _DONE { - return false, nil + s.err = nil + } else { + s.err = s.c.error(r[0]) } - return false, s.c.error(r[0]) + return false +} + +func (s *Stmt) Err() error { + return s.err } func (s *Stmt) BindBool(param int, value bool) error {