const std = @import("std"); const mem = std.mem; const sqlite = @import("sqlite"); pub const Sqlite3Database = 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, }; // 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)), }; pub const Error = error{ExtendedResultCode}; pub const Self = @This(); pub fn init(path: []const u8) Error!Self { var handle: ?*sqlite.sqlite3 = null; const result = sqlite.sqlite3_open(path.ptr, &handle); const primary_code = @as(PrimaryResultCode, @enumFromInt(result)); switch (primary_code) { .ok => .{}, else => { const code = sqlite.sqlite3_extended_errcode(handle); return error.@as(ExtendedResultCode, @enumFromInt(code)); }, } return .{ .handle = handle }; } }; test { const db: Sqlite3Database = try .init(":memory:"); _ = db; std.debug.print("asdf", .{}); }