From 188373fd0a0031c159935444afd601ee4218de1b Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Thu, 31 Dec 2020 22:04:08 +0100 Subject: add proper error types * Add SQLiteError and various SQLiteExtendedXYZError * Replace old errors with the SQLite ones where appropriate Fixes #8 --- error.zig | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sqlite.zig | 15 ++-- 2 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 error.zig diff --git a/error.zig b/error.zig new file mode 100644 index 0000000..bcccdaf --- /dev/null +++ b/error.zig @@ -0,0 +1,240 @@ +const std = @import("std"); + +const c = @cImport({ + @cInclude("sqlite3.h"); +}); + +pub const SQLiteExtendedIOError = error{ + SQLiteIOErrRead, + SQLiteIOErrShortRead, + SQLiteIOErrWrite, + SQLiteIOErrFsync, + SQLiteIOErrDirFsync, + SQLiteIOErrTruncate, + SQLiteIOErrFstat, + SQLiteIOErrUnlock, + SQLiteIOErrRDLock, + SQLiteIOErrDelete, + SQLiteIOErrBlocked, + SQLiteIOErrNoMem, + SQLiteIOErrAccess, + SQLiteIOErrCheckReservedLock, + SQLiteIOErrLock, + SQLiteIOErrClose, + SQLiteIOErrDirClose, + SQLiteIOErrSHMOpen, + SQLiteIOErrSHMSize, + SQLiteIOErrSHMLock, + SQLiteIOErrSHMMap, + SQLiteIOErrSeek, + SQLiteIOErrDeleteNoEnt, + SQLiteIOErrMmap, + SQLiteIOErrGetTempPath, + SQLiteIOErrConvPath, + SQLiteIOErrVnode, + SQLiteIOErrAuth, + SQLiteIOErrBeginAtomic, + SQLiteIOErrCommitAtomic, + SQLiteIOErrRollbackAtomic, + SQLiteIOErrData, + SQLiteIOErrCorruptFS, +}; + +pub const SQLiteExtendedCantOpenError = error{ + SQLiteCantOpenNoTempDir, + SQLiteCantOpenIsDir, + SQLiteCantOpenFullPath, + SQLiteCantOpenConvPath, + SQLiteCantOpenDirtyWAL, + SQLiteCantOpenSymlink, +}; + +pub const SQLiteExtendedReadOnlyError = error{ + SQLiteReadOnlyRecovery, + SQLiteReadOnlyCantLock, + SQLiteReadOnlyRollback, + SQLiteReadOnlyDBMoved, + SQLiteReadOnlyCantInit, + SQLiteReadOnlyDirectory, +}; + +pub const SQLiteExtendedConstraintError = error{ + SQLiteConstraintCheck, + SQLiteConstraintCommitHook, + SQLiteConstraintForeignKey, + SQLiteConstraintFunction, + SQLiteConstraintNotNull, + SQLiteConstraintPrimaryKey, + SQLiteConstraintTrigger, + SQLiteConstraintUnique, + SQLiteConstraintVTab, + SQLiteConstraintRowID, + SQLiteConstraintPinned, +}; + +pub const SQLiteExtendedError = error{ + SQLiteErrorMissingCollSeq, + SQLiteErrorRetry, + SQLiteErrorSnapshot, + + SQLiteLockedSharedCache, + SQLiteLockedVTab, + + SQLiteBusyRecovery, + SQLiteBusySnapshot, + SQLiteBusyTimeout, + + SQLiteCorruptVTab, + SQLiteCorruptSequence, + SQLiteCorruptIndex, + + SQLiteAbortRollback, +}; + +pub const SQLiteError = error{ + SQLiteError, + SQLiteInternal, + SQLitePerm, + SQLiteAbort, + SQLiteBusy, + SQLiteLocked, + SQLiteNoMem, + SQLiteReadOnly, + SQLiteInterrupt, + SQLiteIOErr, + SQLiteCorrupt, + SQLiteNotFound, + SQLiteFull, + SQLiteCantOpen, + SQLiteProtocol, + SQLiteEmpty, + SQLiteSchema, + SQLiteTooBig, + SQLiteConstraint, + SQLiteMismatch, + SQLiteMisuse, + SQLiteNoLFS, + SQLiteAuth, + SQLiteRange, + SQLiteNotADatabase, + SQLiteNotice, + SQLiteWarning, +}; + +pub const Error = SQLiteError || + SQLiteExtendedError || + SQLiteExtendedIOError || + SQLiteExtendedCantOpenError || + SQLiteExtendedReadOnlyError || + SQLiteExtendedConstraintError; + +pub fn errorFromResultCode(code: c_int) Error { + return switch (code) { + c.SQLITE_ERROR => error.SQLiteError, + c.SQLITE_INTERNAL => error.SQLiteInternal, + c.SQLITE_PERM => error.SQLitePerm, + c.SQLITE_ABORT => error.SQLiteAbort, + c.SQLITE_BUSY => error.SQLiteBusy, + c.SQLITE_LOCKED => error.SQLiteLocked, + c.SQLITE_NOMEM => error.SQLiteNoMem, + c.SQLITE_READONLY => error.SQLiteReadOnly, + c.SQLITE_INTERRUPT => error.SQLiteInterrupt, + c.SQLITE_IOERR => error.SQLiteIOErr, + c.SQLITE_CORRUPT => error.SQLiteCorrupt, + c.SQLITE_NOTFOUND => error.SQLiteNotFound, + c.SQLITE_FULL => error.SQLiteFull, + c.SQLITE_CANTOPEN => error.SQLiteCantOpen, + c.SQLITE_PROTOCOL => error.SQLiteProtocol, + c.SQLITE_EMPTY => error.SQLiteEmpty, + c.SQLITE_SCHEMA => error.SQLiteSchema, + c.SQLITE_TOOBIG => error.SQLiteTooBig, + c.SQLITE_CONSTRAINT => error.SQLiteConstraint, + c.SQLITE_MISMATCH => error.SQLiteMismatch, + c.SQLITE_MISUSE => error.SQLiteMisuse, + c.SQLITE_NOLFS => error.SQLiteNoLFS, + c.SQLITE_AUTH => error.SQLiteAuth, + c.SQLITE_RANGE => error.SQLiteRange, + c.SQLITE_NOTADB => error.SQLiteNotADatabase, + c.SQLITE_NOTICE => error.SQLiteNotice, + c.SQLITE_WARNING => error.SQLiteWarning, + + c.SQLITE_ERROR_MISSING_COLLSEQ => error.SQLiteErrorMissingCollSeq, + c.SQLITE_ERROR_RETRY => error.SQLiteErrorRetry, + c.SQLITE_ERROR_SNAPSHOT => error.SQLiteErrorSnapshot, + + c.SQLITE_IOERR_READ => error.SQLiteIOErrRead, + c.SQLITE_IOERR_SHORT_READ => error.SQLiteIOErrShortRead, + c.SQLITE_IOERR_WRITE => error.SQLiteIOErrWrite, + c.SQLITE_IOERR_FSYNC => error.SQLiteIOErrFsync, + c.SQLITE_IOERR_DIR_FSYNC => error.SQLiteIOErrDirFsync, + c.SQLITE_IOERR_TRUNCATE => error.SQLiteIOErrTruncate, + c.SQLITE_IOERR_FSTAT => error.SQLiteIOErrFstat, + c.SQLITE_IOERR_UNLOCK => error.SQLiteIOErrUnlock, + c.SQLITE_IOERR_RDLOCK => error.SQLiteIOErrRDLock, + c.SQLITE_IOERR_DELETE => error.SQLiteIOErrDelete, + c.SQLITE_IOERR_BLOCKED => error.SQLiteIOErrBlocked, + c.SQLITE_IOERR_NOMEM => error.SQLiteIOErrNoMem, + c.SQLITE_IOERR_ACCESS => error.SQLiteIOErrAccess, + c.SQLITE_IOERR_CHECKRESERVEDLOCK => error.SQLiteIOErrCheckReservedLock, + c.SQLITE_IOERR_LOCK => error.SQLiteIOErrLock, + c.SQLITE_IOERR_CLOSE => error.SQLiteIOErrClose, + c.SQLITE_IOERR_DIR_CLOSE => error.SQLiteIOErrDirClose, + c.SQLITE_IOERR_SHMOPEN => error.SQLiteIOErrSHMOpen, + c.SQLITE_IOERR_SHMSIZE => error.SQLiteIOErrSHMSize, + c.SQLITE_IOERR_SHMLOCK => error.SQLiteIOErrSHMLock, + c.SQLITE_IOERR_SHMMAP => error.SQLiteIOErrSHMMap, + c.SQLITE_IOERR_SEEK => error.SQLiteIOErrSeek, + c.SQLITE_IOERR_DELETE_NOENT => error.SQLiteIOErrDeleteNoEnt, + c.SQLITE_IOERR_MMAP => error.SQLiteIOErrMmap, + c.SQLITE_IOERR_GETTEMPPATH => error.SQLiteIOErrGetTempPath, + c.SQLITE_IOERR_CONVPATH => error.SQLiteIOErrConvPath, + c.SQLITE_IOERR_VNODE => error.SQLiteIOErrVnode, + c.SQLITE_IOERR_AUTH => error.SQLiteIOErrAuth, + c.SQLITE_IOERR_BEGIN_ATOMIC => error.SQLiteIOErrBeginAtomic, + c.SQLITE_IOERR_COMMIT_ATOMIC => error.SQLiteIOErrCommitAtomic, + c.SQLITE_IOERR_ROLLBACK_ATOMIC => error.SQLiteIOErrRollbackAtomic, + c.SQLITE_IOERR_DATA => error.SQLiteIOErrData, + c.SQLITE_IOERR_CORRUPTFS => error.SQLiteIOErrCorruptFS, + + c.SQLITE_LOCKED_SHAREDCACHE => error.SQLiteLockedSharedCache, + c.SQLITE_LOCKED_VTAB => error.SQLiteLockedVTab, + + c.SQLITE_BUSY_RECOVERY => error.SQLiteBusyRecovery, + c.SQLITE_BUSY_SNAPSHOT => error.SQLiteBusySnapshot, + c.SQLITE_BUSY_TIMEOUT => error.SQLiteBusyTimeout, + + c.SQLITE_CANTOPEN_NOTEMPDIR => error.SQLiteCantOpenNoTempDir, + c.SQLITE_CANTOPEN_ISDIR => error.SQLiteCantOpenIsDir, + c.SQLITE_CANTOPEN_FULLPATH => error.SQLiteCantOpenFullPath, + c.SQLITE_CANTOPEN_CONVPATH => error.SQLiteCantOpenConvPath, + c.SQLITE_CANTOPEN_DIRTYWAL => error.SQLiteCantOpenDirtyWAL, + c.SQLITE_CANTOPEN_SYMLINK => error.SQLiteCantOpenSymlink, + + c.SQLITE_CORRUPT_VTAB => error.SQLiteCorruptVTab, + c.SQLITE_CORRUPT_SEQUENCE => error.SQLiteCorruptSequence, + c.SQLITE_CORRUPT_INDEX => error.SQLiteCorruptIndex, + + c.SQLITE_READONLY_RECOVERY => error.SQLiteReadOnlyRecovery, + c.SQLITE_READONLY_CANTLOCK => error.SQLiteReadOnlyCantLock, + c.SQLITE_READONLY_ROLLBACK => error.SQLiteReadOnlyRollback, + c.SQLITE_READONLY_DBMOVED => error.SQLiteReadOnlyDBMoved, + c.SQLITE_READONLY_CANTINIT => error.SQLiteReadOnlyCantInit, + c.SQLITE_READONLY_DIRECTORY => error.SQLiteReadOnlyDirectory, + + c.SQLITE_ABORT_ROLLBACK => error.SQLiteAbortRollback, + + c.SQLITE_CONSTRAINT_CHECK => error.SQLiteConstraintCheck, + c.SQLITE_CONSTRAINT_COMMITHOOK => error.SQLiteConstraintCommitHook, + c.SQLITE_CONSTRAINT_FOREIGNKEY => error.SQLiteConstraintForeignKey, + c.SQLITE_CONSTRAINT_FUNCTION => error.SQLiteConstraintFunction, + c.SQLITE_CONSTRAINT_NOTNULL => error.SQLiteConstraintNotNull, + c.SQLITE_CONSTRAINT_PRIMARYKEY => error.SQLiteConstraintPrimaryKey, + c.SQLITE_CONSTRAINT_TRIGGER => error.SQLiteConstraintTrigger, + c.SQLITE_CONSTRAINT_UNIQUE => error.SQLiteConstraintUnique, + c.SQLITE_CONSTRAINT_VTAB => error.SQLiteConstraintVTab, + c.SQLITE_CONSTRAINT_ROWID => error.SQLiteConstraintRowID, + c.SQLITE_CONSTRAINT_PINNED => error.SQLiteConstraintPinned, + + else => std.debug.panic("invalid result code {}", .{code}), + }; +} diff --git a/sqlite.zig b/sqlite.zig index 6abedc4..4aae0e6 100644 --- a/sqlite.zig +++ b/sqlite.zig @@ -9,6 +9,7 @@ const c = @cImport({ }); usingnamespace @import("query.zig"); +usingnamespace @import("error.zig"); const logger = std.log.scoped(.sqlite); @@ -42,8 +43,6 @@ pub const InitOptions = struct { threading_mode: ThreadingMode = .Serialized, }; -pub const Error = error{}; - /// DetailedError contains a SQLite error code and error message. pub const DetailedError = struct { code: usize, @@ -128,7 +127,7 @@ pub const Db = struct { var db: ?*c.sqlite3 = undefined; const result = c.sqlite3_open_v2(path, &db, flags, null); if (result != c.SQLITE_OK or db == null) { - return error.CannotOpenDatabase; + return errorFromResultCode(result); } self.db = db.?; @@ -141,7 +140,7 @@ pub const Db = struct { var db: ?*c.sqlite3 = undefined; const result = c.sqlite3_open_v2(":memory:", &db, flags, null); if (result != c.SQLITE_OK or db == null) { - return error.CannotOpenDatabase; + return errorFromResultCode(result); } self.db = db.?; @@ -292,7 +291,7 @@ pub fn Iterator(comptime Type: type) type { return null; } if (result != c.SQLITE_ROW) { - return error.SQLiteStepError; + return errorFromResultCode(result); } const columns = c.sqlite3_column_count(self.stmt); @@ -332,7 +331,7 @@ pub fn Iterator(comptime Type: type) type { return null; } if (result != c.SQLITE_ROW) { - return error.SQLiteStepError; + return errorFromResultCode(result); } const columns = c.sqlite3_column_count(self.stmt); @@ -649,7 +648,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t null, ); if (result != c.SQLITE_OK) { - return error.CannotPrepareStatement; + return errorFromResultCode(result); } break :blk tmp.?; }; @@ -754,7 +753,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t const result = c.sqlite3_step(self.stmt); switch (result) { c.SQLITE_DONE => {}, - c.SQLITE_BUSY => return error.SQLiteBusy, + c.SQLITE_BUSY => return errorFromResultCode(result), else => std.debug.panic("invalid result {}", .{result}), } } -- cgit v1.2.3 From a39130b6b8e4900c10697a345fd890468503f6bd Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Thu, 31 Dec 2020 22:08:55 +0100 Subject: fix tests with the new errors --- sqlite.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlite.zig b/sqlite.zig index 4aae0e6..ec46ed9 100644 --- a/sqlite.zig +++ b/sqlite.zig @@ -1402,7 +1402,7 @@ test "sqlite: failing open" { .open_flags = .{}, .mode = .{ .File = "/tmp/not_existing.db" }, }); - testing.expectError(error.CannotOpenDatabase, res); + testing.expectError(error.SQLiteCantOpen, res); } test "sqlite: failing prepare statement" { @@ -1410,7 +1410,7 @@ test "sqlite: failing prepare statement" { try db.init(initOptions()); const result = db.prepare("SELECT id FROM foobar"); - testing.expectError(error.CannotPrepareStatement, result); + testing.expectError(error.SQLiteError, result); const detailed_err = db.getDetailedError(); testing.expectEqual(@as(usize, 1), detailed_err.code); -- cgit v1.2.3 From 46f961bf850829dc0358ea8d1c4ea81b9f2508a7 Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Thu, 31 Dec 2020 22:41:19 +0100 Subject: fix error checks based on the sqlite version --- error.zig | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/error.zig b/error.zig index bcccdaf..eb2f00c 100644 --- a/error.zig +++ b/error.zig @@ -129,6 +129,44 @@ pub const Error = SQLiteError || SQLiteExtendedConstraintError; pub fn errorFromResultCode(code: c_int) Error { + // TODO(vincent): can we do something with comptime here ? + // The version number is always static and defined by sqlite. + + // These errors are only available since 3.25.0. + if (c.SQLITE_VERSION_NUMBER >= 3025000) { + switch (code) { + c.SQLITE_ERROR_SNAPSHOT => return error.SQLiteErrorSnapshot, + c.SQLITE_LOCKED_VTAB => return error.SQLiteLockedVTab, + c.SQLITE_CANTOPEN_DIRTYWAL => return error.SQLiteCantOpenDirtyWAL, + c.SQLITE_CORRUPT_SEQUENCE => return error.SQLiteCorruptSequence, + else => {}, + } + } + // These errors are only available since 3.31.0. + if (c.SQLITE_VERSION_NUMBER >= 3031000) { + switch (code) { + c.SQLITE_CANTOPEN_SYMLINK => return error.SQLiteCantOpenSymlink, + c.SQLITE_CONSTRAINT_PINNED => return error.SQLiteConstraintPinned, + else => {}, + } + } + // These errors are only available since 3.32.0. + if (c.SQLITE_VERSION_NUMBER >= 3032000) { + switch (code) { + c.SQLITE_IOERR_DATA => return error.SQLiteIOErrData, // See https://sqlite.org/cksumvfs.html + c.SQLITE_BUSY_TIMEOUT => return error.SQLiteBusyTimeout, + c.SQLITE_CORRUPT_INDEX => return error.SQLiteCorruptIndex, + else => {}, + } + } + // These errors are only available since 3.34.0. + if (c.SQLITE_VERSION_NUMBER >= 3034000) { + switch (code) { + c.SQLITE_IOERR_CORRUPTFS => return error.SQLiteIOErrCorruptFS, + else => {}, + } + } + return switch (code) { c.SQLITE_ERROR => error.SQLiteError, c.SQLITE_INTERNAL => error.SQLiteInternal, @@ -160,7 +198,6 @@ pub fn errorFromResultCode(code: c_int) Error { c.SQLITE_ERROR_MISSING_COLLSEQ => error.SQLiteErrorMissingCollSeq, c.SQLITE_ERROR_RETRY => error.SQLiteErrorRetry, - c.SQLITE_ERROR_SNAPSHOT => error.SQLiteErrorSnapshot, c.SQLITE_IOERR_READ => error.SQLiteIOErrRead, c.SQLITE_IOERR_SHORT_READ => error.SQLiteIOErrShortRead, @@ -193,26 +230,18 @@ pub fn errorFromResultCode(code: c_int) Error { c.SQLITE_IOERR_BEGIN_ATOMIC => error.SQLiteIOErrBeginAtomic, c.SQLITE_IOERR_COMMIT_ATOMIC => error.SQLiteIOErrCommitAtomic, c.SQLITE_IOERR_ROLLBACK_ATOMIC => error.SQLiteIOErrRollbackAtomic, - c.SQLITE_IOERR_DATA => error.SQLiteIOErrData, - c.SQLITE_IOERR_CORRUPTFS => error.SQLiteIOErrCorruptFS, c.SQLITE_LOCKED_SHAREDCACHE => error.SQLiteLockedSharedCache, - c.SQLITE_LOCKED_VTAB => error.SQLiteLockedVTab, c.SQLITE_BUSY_RECOVERY => error.SQLiteBusyRecovery, c.SQLITE_BUSY_SNAPSHOT => error.SQLiteBusySnapshot, - c.SQLITE_BUSY_TIMEOUT => error.SQLiteBusyTimeout, c.SQLITE_CANTOPEN_NOTEMPDIR => error.SQLiteCantOpenNoTempDir, c.SQLITE_CANTOPEN_ISDIR => error.SQLiteCantOpenIsDir, c.SQLITE_CANTOPEN_FULLPATH => error.SQLiteCantOpenFullPath, c.SQLITE_CANTOPEN_CONVPATH => error.SQLiteCantOpenConvPath, - c.SQLITE_CANTOPEN_DIRTYWAL => error.SQLiteCantOpenDirtyWAL, - c.SQLITE_CANTOPEN_SYMLINK => error.SQLiteCantOpenSymlink, c.SQLITE_CORRUPT_VTAB => error.SQLiteCorruptVTab, - c.SQLITE_CORRUPT_SEQUENCE => error.SQLiteCorruptSequence, - c.SQLITE_CORRUPT_INDEX => error.SQLiteCorruptIndex, c.SQLITE_READONLY_RECOVERY => error.SQLiteReadOnlyRecovery, c.SQLITE_READONLY_CANTLOCK => error.SQLiteReadOnlyCantLock, @@ -233,7 +262,6 @@ pub fn errorFromResultCode(code: c_int) Error { c.SQLITE_CONSTRAINT_UNIQUE => error.SQLiteConstraintUnique, c.SQLITE_CONSTRAINT_VTAB => error.SQLiteConstraintVTab, c.SQLITE_CONSTRAINT_ROWID => error.SQLiteConstraintRowID, - c.SQLITE_CONSTRAINT_PINNED => error.SQLiteConstraintPinned, else => std.debug.panic("invalid result code {}", .{code}), }; -- cgit v1.2.3