const std = @import("std"); const sqlite = @import("sqlite"); pub const Database = struct { handle: *sqlite.sqlite3, pub const Error = set: { var set: type = error{}; 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)); } break :set set; }; pub const Kind = union(enum) { temp_in_memory, temp_on_disk, path: []const u8, }; // 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: 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, fn as(self: Primary, comptime T: type) T { return @as(T, @intFromEnum(self)); } }; // 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: Database = try .init(.temp_in_memory); _ = db; }