aboutsummaryrefslogtreecommitdiff
path: root/src/db/sqlite.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/db/sqlite.zig')
-rw-r--r--src/db/sqlite.zig371
1 files changed, 200 insertions, 171 deletions
diff --git a/src/db/sqlite.zig b/src/db/sqlite.zig
index ad76992..1e45537 100644
--- a/src/db/sqlite.zig
+++ b/src/db/sqlite.zig
@@ -1,192 +1,221 @@
const std = @import("std");
-const mem = std.mem;
const sqlite = @import("sqlite");
-pub const Sqlite3Database = struct {
+pub const Database = struct {
handle: *sqlite.sqlite3,
- // FIXME: this is shit, generate these enums at comptime where
- // primary and extended codes are given as tuples
- // zig fmt: off
- pub const PrimaryResultCode = enum(u8) {
- /// Successful result.
- ok = 0,
- /// Generic error.
- @"error" = 1,
- /// Internal logic error in SQLite.
- internal = 2,
- /// Access permission denied.
- perm = 3,
- /// Callback routine requested an abort.
- abort = 4,
- /// The database file is locked.
- busy = 5,
- /// A table in the database is locked.
- locked = 6,
- /// A malloc() failed.
- nomem = 7,
- /// Attempt to write a readonly database.
- readonly = 8,
- /// Operation terminated by sqlite3_interrupt().
- interrupt = 9,
- /// Some kind of disk I/O error occurred.
- ioerr = 10,
- /// The database disk image is malformed.
- corrupt = 11,
- /// Unknown opcode in sqlite3_file_control().
- notfound = 12,
- /// Insertion failed because database is full.
- full = 13,
- /// Unable to open the database file.
- cantopen = 14,
- /// Database lock protocol error.
- protocol = 15,
- /// Internal use only.
- empty = 16,
- /// The database schema changed.
- schema = 17,
- /// String or BLOB exceeds size limit.
- toobig = 18,
- /// Abort due to constraint violation.
- constraint = 19,
- /// Data type mismatch.
- mismatch = 20,
- /// Library used incorrectly.
- misuse = 21,
- /// Uses OS features not supported on host.
- nolfs = 22,
- /// Authorization denied.
- auth = 23,
- /// Not used.
- format = 24,
- /// 2nd parameter to sqlite3_bind out of range.
- range = 25,
- /// File opened that is not a database file.
- notadb = 26,
- /// Notifications from sqlite3_log().
- notice = 27,
- /// Warnings from sqlite3_log().
- warning = 28,
- /// sqlite3_step() has another row ready.
- row = 100,
- /// sqlite3_step() has finished executing.
- done = 101,
- };
+ pub const Error = set: {
+ var set: type = error{};
- // zig fmt: off
- pub const ExtendedResultCode = enum(i32) {
- err_missing_collseq = (@as(i32, @intFromEnum(PrimaryResultCode.@"error" )) | (1 << 8)),
- err_retry = (@as(i32, @intFromEnum(PrimaryResultCode.@"error" )) | (2 << 8)),
- err_snapshot = (@as(i32, @intFromEnum(PrimaryResultCode.@"error" )) | (3 << 8)),
- err_reservesize = (@as(i32, @intFromEnum(PrimaryResultCode.@"error" )) | (4 << 8)),
- err_key = (@as(i32, @intFromEnum(PrimaryResultCode.@"error" )) | (5 << 8)),
- err_unable = (@as(i32, @intFromEnum(PrimaryResultCode.@"error" )) | (6 << 8)),
- ioerr_read = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (1 << 8)),
- ioerr_short_read = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (2 << 8)),
- ioerr_write = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (3 << 8)),
- ioerr_fsync = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (4 << 8)),
- ioerr_dir_fsync = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (5 << 8)),
- ioerr_truncate = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (6 << 8)),
- ioerr_fstat = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (7 << 8)),
- ioerr_unlock = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (8 << 8)),
- ioerr_rdlock = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (9 << 8)),
- ioerr_delete = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (10 << 8)),
- ioerr_blocked = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (11 << 8)),
- ioerr_nomem = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (12 << 8)),
- ioerr_access = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (13 << 8)),
- ioerr_checkreservedlock = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (14 << 8)),
- ioerr_lock = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (15 << 8)),
- ioerr_close = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (16 << 8)),
- ioerr_dir_close = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (17 << 8)),
- ioerr_shmopen = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (18 << 8)),
- ioerr_shmsize = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (19 << 8)),
- ioerr_shmlock = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (20 << 8)),
- ioerr_shmmap = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (21 << 8)),
- ioerr_seek = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (22 << 8)),
- ioerr_delete_noent = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (23 << 8)),
- ioerr_mmap = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (24 << 8)),
- ioerr_gettemppath = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (25 << 8)),
- ioerr_convpath = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (26 << 8)),
- ioerr_vnode = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (27 << 8)),
- ioerr_auth = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (28 << 8)),
- ioerr_begin_atomic = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (29 << 8)),
- ioerr_commit_atomic = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (30 << 8)),
- ioerr_rollback_atomic = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (31 << 8)),
- ioerr_data = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (32 << 8)),
- ioerr_corruptfs = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (33 << 8)),
- ioerr_in_page = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (34 << 8)),
- ioerr_badkey = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (35 << 8)),
- ioerr_codec = (@as(i32, @intFromEnum(PrimaryResultCode.ioerr )) | (36 << 8)),
- locked_sharedcache = (@as(i32, @intFromEnum(PrimaryResultCode.locked )) | (1 << 8)),
- locked_vtab = (@as(i32, @intFromEnum(PrimaryResultCode.locked )) | (2 << 8)),
- busy_recovery = (@as(i32, @intFromEnum(PrimaryResultCode.busy )) | (1 << 8)),
- busy_snapshot = (@as(i32, @intFromEnum(PrimaryResultCode.busy )) | (2 << 8)),
- busy_timeout = (@as(i32, @intFromEnum(PrimaryResultCode.busy )) | (3 << 8)),
- cantopen_notempdir = (@as(i32, @intFromEnum(PrimaryResultCode.cantopen )) | (1 << 8)),
- cantopen_isdir = (@as(i32, @intFromEnum(PrimaryResultCode.cantopen )) | (2 << 8)),
- cantopen_fullpath = (@as(i32, @intFromEnum(PrimaryResultCode.cantopen )) | (3 << 8)),
- cantopen_convpath = (@as(i32, @intFromEnum(PrimaryResultCode.cantopen )) | (4 << 8)),
- /// Not used.
- cantopen_dirtywal = (@as(i32, @intFromEnum(PrimaryResultCode.cantopen )) | (5 << 8)),
- cantopen_symlink = (@as(i32, @intFromEnum(PrimaryResultCode.cantopen )) | (6 << 8)),
- corrupt_vtab = (@as(i32, @intFromEnum(PrimaryResultCode.corrupt )) | (1 << 8)),
- corrupt_sequence = (@as(i32, @intFromEnum(PrimaryResultCode.corrupt )) | (2 << 8)),
- corrupt_index = (@as(i32, @intFromEnum(PrimaryResultCode.corrupt )) | (3 << 8)),
- readonly_recovery = (@as(i32, @intFromEnum(PrimaryResultCode.readonly )) | (1 << 8)),
- readonly_cantlock = (@as(i32, @intFromEnum(PrimaryResultCode.readonly )) | (2 << 8)),
- readonly_rollback = (@as(i32, @intFromEnum(PrimaryResultCode.readonly )) | (3 << 8)),
- readonly_dbmoved = (@as(i32, @intFromEnum(PrimaryResultCode.readonly )) | (4 << 8)),
- readonly_cantinit = (@as(i32, @intFromEnum(PrimaryResultCode.readonly )) | (5 << 8)),
- readonly_directory = (@as(i32, @intFromEnum(PrimaryResultCode.readonly )) | (6 << 8)),
- abort_rollback = (@as(i32, @intFromEnum(PrimaryResultCode.abort )) | (2 << 8)),
- constraint_check = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (1 << 8)),
- constraint_commithook = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (2 << 8)),
- constraint_foreignkey = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (3 << 8)),
- constraint_function = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (4 << 8)),
- constraint_notnull = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (5 << 8)),
- constraint_primarykey = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (6 << 8)),
- constraint_trigger = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (7 << 8)),
- constraint_unique = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (8 << 8)),
- constraint_vtab = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (9 << 8)),
- constraint_rowid = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (10 << 8)),
- constraint_pinned = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (11 << 8)),
- constraint_datatype = (@as(i32, @intFromEnum(PrimaryResultCode.constraint )) | (12 << 8)),
- notice_recover_wal = (@as(i32, @intFromEnum(PrimaryResultCode.notice )) | (1 << 8)),
- notice_recover_rollback = (@as(i32, @intFromEnum(PrimaryResultCode.notice )) | (2 << 8)),
- notice_rbu = (@as(i32, @intFromEnum(PrimaryResultCode.notice )) | (3 << 8)),
- warning_autoindex = (@as(i32, @intFromEnum(PrimaryResultCode.warning )) | (1 << 8)),
- auth_user = (@as(i32, @intFromEnum(PrimaryResultCode.auth )) | (1 << 8)),
- ok_load_permanently = (@as(i32, @intFromEnum(PrimaryResultCode.ok )) | (1 << 8)),
- /// Internal only.
- ok_symlink = (@as(i32, @intFromEnum(PrimaryResultCode.ok )) | (2 << 8)),
- };
+ for (std.meta.fieldNames(Result.Primary)) |name| {
+ set = set || @TypeOf(@field(anyerror, name));
+ }
+ for (std.meta.fieldNames(Result.Extended)) |name| {
+ set = set || @TypeOf(@field(anyerror, name));
+ }
- pub const Error = error{ExtendedResultCode};
+ break :set set;
+ };
- pub const Self = @This();
+ pub const Kind = union(enum) {
+ temp_in_memory,
+ temp_on_disk,
+ path: []const u8,
+ };
- pub fn init(path: []const u8) Error!Self {
+ // Source: https://sqlite.org/c3ref/open.html
+ pub fn init(kind: Kind) Error!Database {
+ const name = switch (kind) {
+ .temp_in_memory => ":memory:",
+ .temp_on_disk => "",
+ .path => |path| path,
+ };
var handle: ?*sqlite.sqlite3 = null;
- const result = sqlite.sqlite3_open(path.ptr, &handle);
- const primary_code = @as(PrimaryResultCode, @enumFromInt(result));
+ const result: Result = .from(sqlite.sqlite3_open(name.ptr, &handle));
+
+ switch (result.primary()) {
+ .ok => {},
+ inline else => |code| return @field(anyerror, @tagName(code)),
+ }
+
+ return .{ .handle = handle.? };
+ }
+};
+
+// Source: https://sqlite.org/rescode.html
+pub const Result = enum(i32) {
+ _,
+
+ // zig fmt: off
+ pub const Primary = enum(u8) {
+ /// Successful result.
+ ok = 0,
+ /// Generic error.
+ @"error" = 1,
+ /// Internal logic error in SQLite.
+ internal = 2,
+ /// Access permission denied.
+ perm = 3,
+ /// Callback routine requested an abort.
+ abort = 4,
+ /// The database file is locked.
+ busy = 5,
+ /// A table in the database is locked.
+ locked = 6,
+ /// A malloc() failed.
+ nomem = 7,
+ /// Attempt to write a readonly database.
+ readonly = 8,
+ /// Operation terminated by sqlite3_interrupt().
+ interrupt = 9,
+ /// Some kind of disk I/O error occurred.
+ ioerr = 10,
+ /// The database disk image is malformed.
+ corrupt = 11,
+ /// Unknown opcode in sqlite3_file_control().
+ notfound = 12,
+ /// Insertion failed because database is full.
+ full = 13,
+ /// Unable to open the database file.
+ cantopen = 14,
+ /// Database lock protocol error.
+ protocol = 15,
+ /// Internal use only.
+ empty = 16,
+ /// The database schema changed.
+ schema = 17,
+ /// String or BLOB exceeds size limit.
+ toobig = 18,
+ /// Abort due to constraint violation.
+ constraint = 19,
+ /// Data type mismatch.
+ mismatch = 20,
+ /// Library used incorrectly.
+ misuse = 21,
+ /// Uses OS features not supported on host.
+ nolfs = 22,
+ /// Authorization denied.
+ auth = 23,
+ /// Not used.
+ format = 24,
+ /// 2nd parameter to sqlite3_bind out of range.
+ range = 25,
+ /// File opened that is not a database file.
+ notadb = 26,
+ /// Notifications from sqlite3_log().
+ notice = 27,
+ /// Warnings from sqlite3_log().
+ warning = 28,
+ /// sqlite3_step() has another row ready.
+ row = 100,
+ /// sqlite3_step() has finished executing.
+ done = 101,
- switch (primary_code) {
- .ok => .{},
- else => {
- const code = sqlite.sqlite3_extended_errcode(handle);
- return error.@as(ExtendedResultCode, @enumFromInt(code));
- },
+ fn as(self: Primary, comptime T: type) T {
+ return @as(T, @intFromEnum(self));
}
+ };
- return .{ .handle = handle };
+ // zig fmt: off
+ pub const Extended = enum(i32) {
+ error_missing_collseq = (Primary.@"error".as(i32) | ( 1 << 8)),
+ error_retry = (Primary.@"error".as(i32) | ( 2 << 8)),
+ error_snapshot = (Primary.@"error".as(i32) | ( 3 << 8)),
+ error_reservesize = (Primary.@"error".as(i32) | ( 4 << 8)),
+ error_key = (Primary.@"error".as(i32) | ( 5 << 8)),
+ error_unable = (Primary.@"error".as(i32) | ( 6 << 8)),
+ ioerr_read = (Primary.ioerr.as(i32) | ( 1 << 8)),
+ ioerr_short_read = (Primary.ioerr.as(i32) | ( 2 << 8)),
+ ioerr_write = (Primary.ioerr.as(i32) | ( 3 << 8)),
+ ioerr_fsync = (Primary.ioerr.as(i32) | ( 4 << 8)),
+ ioerr_dir_fsync = (Primary.ioerr.as(i32) | ( 5 << 8)),
+ ioerr_truncate = (Primary.ioerr.as(i32) | ( 6 << 8)),
+ ioerr_fstat = (Primary.ioerr.as(i32) | ( 7 << 8)),
+ ioerr_unlock = (Primary.ioerr.as(i32) | ( 8 << 8)),
+ ioerr_rdlock = (Primary.ioerr.as(i32) | ( 9 << 8)),
+ ioerr_delete = (Primary.ioerr.as(i32) | (10 << 8)),
+ ioerr_blocked = (Primary.ioerr.as(i32) | (11 << 8)),
+ ioerr_nomem = (Primary.ioerr.as(i32) | (12 << 8)),
+ ioerr_access = (Primary.ioerr.as(i32) | (13 << 8)),
+ ioerr_checkreservedlock = (Primary.ioerr.as(i32) | (14 << 8)),
+ ioerr_lock = (Primary.ioerr.as(i32) | (15 << 8)),
+ ioerr_close = (Primary.ioerr.as(i32) | (16 << 8)),
+ ioerr_dir_close = (Primary.ioerr.as(i32) | (17 << 8)),
+ ioerr_shmopen = (Primary.ioerr.as(i32) | (18 << 8)),
+ ioerr_shmsize = (Primary.ioerr.as(i32) | (19 << 8)),
+ ioerr_shmlock = (Primary.ioerr.as(i32) | (20 << 8)),
+ ioerr_shmmap = (Primary.ioerr.as(i32) | (21 << 8)),
+ ioerr_seek = (Primary.ioerr.as(i32) | (22 << 8)),
+ ioerr_delete_noent = (Primary.ioerr.as(i32) | (23 << 8)),
+ ioerr_mmap = (Primary.ioerr.as(i32) | (24 << 8)),
+ ioerr_gettemppath = (Primary.ioerr.as(i32) | (25 << 8)),
+ ioerr_convpath = (Primary.ioerr.as(i32) | (26 << 8)),
+ ioerr_vnode = (Primary.ioerr.as(i32) | (27 << 8)),
+ ioerr_auth = (Primary.ioerr.as(i32) | (28 << 8)),
+ ioerr_begin_atomic = (Primary.ioerr.as(i32) | (29 << 8)),
+ ioerr_commit_atomic = (Primary.ioerr.as(i32) | (30 << 8)),
+ ioerr_rollback_atomic = (Primary.ioerr.as(i32) | (31 << 8)),
+ ioerr_data = (Primary.ioerr.as(i32) | (32 << 8)),
+ ioerr_corruptfs = (Primary.ioerr.as(i32) | (33 << 8)),
+ ioerr_in_page = (Primary.ioerr.as(i32) | (34 << 8)),
+ ioerr_badkey = (Primary.ioerr.as(i32) | (35 << 8)),
+ ioerr_codec = (Primary.ioerr.as(i32) | (36 << 8)),
+ locked_sharedcache = (Primary.locked.as(i32) | ( 1 << 8)),
+ locked_vtab = (Primary.locked.as(i32) | ( 2 << 8)),
+ busy_recovery = (Primary.busy.as(i32) | ( 1 << 8)),
+ busy_snapshot = (Primary.busy.as(i32) | ( 2 << 8)),
+ busy_timeout = (Primary.busy.as(i32) | ( 3 << 8)),
+ cantopen_notempdir = (Primary.cantopen.as(i32) | ( 1 << 8)),
+ cantopen_isdir = (Primary.cantopen.as(i32) | ( 2 << 8)),
+ cantopen_fullpath = (Primary.cantopen.as(i32) | ( 3 << 8)),
+ cantopen_convpath = (Primary.cantopen.as(i32) | ( 4 << 8)),
+ cantopen_symlink = (Primary.cantopen.as(i32) | ( 6 << 8)),
+ corrupt_vtab = (Primary.corrupt.as(i32) | ( 1 << 8)),
+ corrupt_sequence = (Primary.corrupt.as(i32) | ( 2 << 8)),
+ corrupt_index = (Primary.corrupt.as(i32) | ( 3 << 8)),
+ readonly_recovery = (Primary.readonly.as(i32) | ( 1 << 8)),
+ readonly_cantlock = (Primary.readonly.as(i32) | ( 2 << 8)),
+ readonly_rollback = (Primary.readonly.as(i32) | ( 3 << 8)),
+ readonly_dbmoved = (Primary.readonly.as(i32) | ( 4 << 8)),
+ readonly_cantinit = (Primary.readonly.as(i32) | ( 5 << 8)),
+ readonly_directory = (Primary.readonly.as(i32) | ( 6 << 8)),
+ abort_rollback = (Primary.abort.as(i32) | ( 2 << 8)),
+ constraint_check = (Primary.constraint.as(i32) | ( 1 << 8)),
+ constraint_commithook = (Primary.constraint.as(i32) | ( 2 << 8)),
+ constraint_foreignkey = (Primary.constraint.as(i32) | ( 3 << 8)),
+ constraint_function = (Primary.constraint.as(i32) | ( 4 << 8)),
+ constraint_notnull = (Primary.constraint.as(i32) | ( 5 << 8)),
+ constraint_primarykey = (Primary.constraint.as(i32) | ( 6 << 8)),
+ constraint_trigger = (Primary.constraint.as(i32) | ( 7 << 8)),
+ constraint_unique = (Primary.constraint.as(i32) | ( 8 << 8)),
+ constraint_vtab = (Primary.constraint.as(i32) | ( 9 << 8)),
+ constraint_rowid = (Primary.constraint.as(i32) | (10 << 8)),
+ constraint_pinned = (Primary.constraint.as(i32) | (11 << 8)),
+ constraint_datatype = (Primary.constraint.as(i32) | (12 << 8)),
+ notice_recover_wal = (Primary.notice.as(i32) | ( 1 << 8)),
+ notice_recover_rollback = (Primary.notice.as(i32) | ( 2 << 8)),
+ notice_rbu = (Primary.notice.as(i32) | ( 3 << 8)),
+ warning_autoindex = (Primary.warning.as(i32) | ( 1 << 8)),
+ auth_user = (Primary.auth.as(i32) | ( 1 << 8)),
+ ok_load_permanently = (Primary.ok.as(i32) | ( 1 << 8)),
+ };
+
+ pub fn from(value: anytype) Result {
+ return @enumFromInt(value);
+ }
+
+ pub fn primary(self: Result) Primary {
+ return @enumFromInt(0x000000FF & @intFromEnum(self));
+ }
+
+ pub fn extended(self: Result) Extended {
+ return @enumFromInt(@intFromEnum(self));
}
};
test {
- const db: Sqlite3Database = try .init(":memory:");
+ const db: Database = try .init(.temp_in_memory);
_ = db;
-
- std.debug.print("asdf", .{});
}