summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--errors.zig56
-rw-r--r--sqlite.zig46
2 files changed, 53 insertions, 49 deletions
diff --git a/errors.zig b/errors.zig
index 0b3172f..654e93d 100644
--- a/errors.zig
+++ b/errors.zig
@@ -1,4 +1,5 @@
1const std = @import("std"); 1const std = @import("std");
2const mem = std.mem;
2 3
3const c = @import("c.zig").c; 4const c = @import("c.zig").c;
4 5
@@ -126,13 +127,13 @@ pub const Error = SQLiteError ||
126 SQLiteExtendedReadOnlyError || 127 SQLiteExtendedReadOnlyError ||
127 SQLiteExtendedConstraintError; 128 SQLiteExtendedConstraintError;
128 129
129fn greaterThanOrEqualsTo(major: u8, minor: u8, patch: u8) bool { 130fn versionGreaterThanOrEqualTo(major: u8, minor: u8, patch: u8) bool {
130 return c.SQLITE_VERSION_NUMBER >= @as(u32, major) * 1000000 + @as(u32, minor) * 1000 + @as(u32, patch); 131 return c.SQLITE_VERSION_NUMBER >= @as(u32, major) * 1000000 + @as(u32, minor) * 1000 + @as(u32, patch);
131} 132}
132 133
133pub fn errorFromResultCode(code: c_int) Error { 134pub fn errorFromResultCode(code: c_int) Error {
134 // These errors are only available since 3.22.0. 135 // These errors are only available since 3.22.0.
135 if (comptime greaterThanOrEqualsTo(3, 22, 0)) { 136 if (comptime versionGreaterThanOrEqualTo(3, 22, 0)) {
136 switch (code) { 137 switch (code) {
137 c.SQLITE_ERROR_MISSING_COLLSEQ => return error.SQLiteErrorMissingCollSeq, 138 c.SQLITE_ERROR_MISSING_COLLSEQ => return error.SQLiteErrorMissingCollSeq,
138 c.SQLITE_ERROR_RETRY => return error.SQLiteErrorRetry, 139 c.SQLITE_ERROR_RETRY => return error.SQLiteErrorRetry,
@@ -143,7 +144,7 @@ pub fn errorFromResultCode(code: c_int) Error {
143 } 144 }
144 145
145 // These errors are only available since 3.25.0. 146 // These errors are only available since 3.25.0.
146 if (comptime greaterThanOrEqualsTo(3, 25, 0)) { 147 if (comptime versionGreaterThanOrEqualTo(3, 25, 0)) {
147 switch (code) { 148 switch (code) {
148 c.SQLITE_ERROR_SNAPSHOT => return error.SQLiteErrorSnapshot, 149 c.SQLITE_ERROR_SNAPSHOT => return error.SQLiteErrorSnapshot,
149 c.SQLITE_LOCKED_VTAB => return error.SQLiteLockedVTab, 150 c.SQLITE_LOCKED_VTAB => return error.SQLiteLockedVTab,
@@ -153,7 +154,7 @@ pub fn errorFromResultCode(code: c_int) Error {
153 } 154 }
154 } 155 }
155 // These errors are only available since 3.31.0. 156 // These errors are only available since 3.31.0.
156 if (comptime greaterThanOrEqualsTo(3, 31, 0)) { 157 if (comptime versionGreaterThanOrEqualTo(3, 31, 0)) {
157 switch (code) { 158 switch (code) {
158 c.SQLITE_CANTOPEN_SYMLINK => return error.SQLiteCantOpenSymlink, 159 c.SQLITE_CANTOPEN_SYMLINK => return error.SQLiteCantOpenSymlink,
159 c.SQLITE_CONSTRAINT_PINNED => return error.SQLiteConstraintPinned, 160 c.SQLITE_CONSTRAINT_PINNED => return error.SQLiteConstraintPinned,
@@ -161,7 +162,7 @@ pub fn errorFromResultCode(code: c_int) Error {
161 } 162 }
162 } 163 }
163 // These errors are only available since 3.32.0. 164 // These errors are only available since 3.32.0.
164 if (comptime greaterThanOrEqualsTo(3, 32, 0)) { 165 if (comptime versionGreaterThanOrEqualTo(3, 32, 0)) {
165 switch (code) { 166 switch (code) {
166 c.SQLITE_IOERR_DATA => return error.SQLiteIOErrData, // See https://sqlite.org/cksumvfs.html 167 c.SQLITE_IOERR_DATA => return error.SQLiteIOErrData, // See https://sqlite.org/cksumvfs.html
167 c.SQLITE_BUSY_TIMEOUT => return error.SQLiteBusyTimeout, 168 c.SQLITE_BUSY_TIMEOUT => return error.SQLiteBusyTimeout,
@@ -170,7 +171,7 @@ pub fn errorFromResultCode(code: c_int) Error {
170 } 171 }
171 } 172 }
172 // These errors are only available since 3.34.0. 173 // These errors are only available since 3.34.0.
173 if (comptime greaterThanOrEqualsTo(3, 34, 0)) { 174 if (comptime versionGreaterThanOrEqualTo(3, 34, 0)) {
174 switch (code) { 175 switch (code) {
175 c.SQLITE_IOERR_CORRUPTFS => return error.SQLiteIOErrCorruptFS, 176 c.SQLITE_IOERR_CORRUPTFS => return error.SQLiteIOErrCorruptFS,
176 else => {}, 177 else => {},
@@ -271,3 +272,46 @@ pub fn errorFromResultCode(code: c_int) Error {
271 else => std.debug.panic("invalid result code {}", .{code}), 272 else => std.debug.panic("invalid result code {}", .{code}),
272 } 273 }
273} 274}
275
276/// DetailedError contains a SQLite error code and error message.
277pub const DetailedError = struct {
278 code: usize,
279 near: i32,
280 message: []const u8,
281
282 pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
283 _ = fmt;
284 _ = options;
285
286 _ = try writer.print("{{code: {}, near: {d}, message: {s}}}", .{ self.code, self.near, self.message });
287 }
288};
289
290pub fn getDetailedErrorFromResultCode(code: c_int) DetailedError {
291 return .{
292 .code = @intCast(usize, code),
293 .near = -1,
294 .message = blk: {
295 const msg = c.sqlite3_errstr(code);
296 break :blk mem.sliceTo(msg, 0);
297 },
298 };
299}
300
301pub fn getErrorOffset(db: *c.sqlite3) i32 {
302 if (comptime versionGreaterThanOrEqualTo(3, 38, 0)) {
303 return c.sqlite3_error_offset(db);
304 }
305 return -1;
306}
307
308pub fn getLastDetailedErrorFromDb(db: *c.sqlite3) DetailedError {
309 return .{
310 .code = @intCast(usize, c.sqlite3_extended_errcode(db)),
311 .near = getErrorOffset(db),
312 .message = blk: {
313 const msg = c.sqlite3_errmsg(db);
314 break :blk mem.sliceTo(msg, 0);
315 },
316 };
317}
diff --git a/sqlite.zig b/sqlite.zig
index 2f8611d..fdc15a5 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -15,6 +15,9 @@ pub const ParsedQuery = @import("query.zig").ParsedQuery;
15const errors = @import("errors.zig"); 15const errors = @import("errors.zig");
16pub const errorFromResultCode = errors.errorFromResultCode; 16pub const errorFromResultCode = errors.errorFromResultCode;
17pub const Error = errors.Error; 17pub const Error = errors.Error;
18pub const DetailedError = errors.DetailedError;
19const getLastDetailedErrorFromDb = errors.getLastDetailedErrorFromDb;
20const getDetailedErrorFromResultCode = errors.getDetailedErrorFromResultCode;
18 21
19const logger = std.log.scoped(.sqlite); 22const logger = std.log.scoped(.sqlite);
20 23
@@ -255,53 +258,10 @@ pub const InitOptions = struct {
255 diags: ?*Diagnostics = null, 258 diags: ?*Diagnostics = null,
256}; 259};
257 260
258/// DetailedError contains a SQLite error code and error message.
259pub const DetailedError = struct {
260 code: usize,
261 near: i32,
262 message: []const u8,
263
264 pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
265 _ = fmt;
266 _ = options;
267
268 _ = try writer.print("{{code: {}, near: {d}, message: {s}}}", .{ self.code, self.near, self.message });
269 }
270};
271
272fn isThreadSafe() bool { 261fn isThreadSafe() bool {
273 return c.sqlite3_threadsafe() > 0; 262 return c.sqlite3_threadsafe() > 0;
274} 263}
275 264
276fn getDetailedErrorFromResultCode(code: c_int) DetailedError {
277 return .{
278 .code = @intCast(usize, code),
279 .near = -1,
280 .message = blk: {
281 const msg = c.sqlite3_errstr(code);
282 break :blk mem.sliceTo(msg, 0);
283 },
284 };
285}
286
287fn getErrorOffset(db: *c.sqlite3) i32 {
288 if (c.SQLITE_VERSION_NUMBER >= 3038000) {
289 return c.sqlite3_error_offset(db);
290 }
291 return -1;
292}
293
294fn getLastDetailedErrorFromDb(db: *c.sqlite3) DetailedError {
295 return .{
296 .code = @intCast(usize, c.sqlite3_extended_errcode(db)),
297 .near = getErrorOffset(db),
298 .message = blk: {
299 const msg = c.sqlite3_errmsg(db);
300 break :blk mem.sliceTo(msg, 0);
301 },
302 };
303}
304
305/// Db is a wrapper around a SQLite database, providing high-level functions for executing queries. 265/// Db is a wrapper around a SQLite database, providing high-level functions for executing queries.
306/// A Db can be opened with a file database or a in-memory database: 266/// A Db can be opened with a file database or a in-memory database:
307/// 267///