diff options
Diffstat (limited to 'src/sqlite.zig')
-rw-r--r-- | src/sqlite.zig | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/sqlite.zig b/src/sqlite.zig new file mode 100644 index 0000000..e0668cc --- /dev/null +++ b/src/sqlite.zig @@ -0,0 +1,101 @@ +const std = @import("std"); +const sqlite = @cImport({ + @cInclude("sqlite3.h"); +}); +const Db = @import("main.zig"); +const OpenError = Db.OpenError; +const PrepareError = Db.PrepareError; +const StepError = Db.StepError; +const ColumnError = Db.ColumnError; +const log = @import("log.zig").scoped_log_t(.sqlite); + +//// Sqlite implementation +pub const Sqlite = @This(); + +allocator: std.mem.Allocator, +c_db: *sqlite.sqlite3, + +pub fn open(allocator: std.mem.Allocator, filename: [:0]const u8) OpenError!Db { + var db: ?*sqlite.sqlite3 = null; + const oo = sqlite.SQLITE_OPEN_CREATE | sqlite.SQLITE_OPEN_READWRITE | sqlite.SQLITE_OPEN_FULLMUTEX; + if (sqlite.sqlite3_open_v2(filename.ptr, &db, oo, null) != sqlite.SQLITE_OK) { + log.err("Sqlite#open: sqlite3_open_v2 error {s}", .{sqlite.sqlite3_errmsg(db)}); + return OpenError.Failed; + } + var sqlite_db = try allocator.create(Sqlite); + sqlite_db.allocator = allocator; + sqlite_db.c_db = db.?; + return Db{ + .ptr = sqlite_db, + .vtable = .{ + .prepare = prepare, + .step = step, + .column_i64 = column_i64, + .column_slice_const_u8 = column_slice_const_u8, + .close_stmt = close_stmt, + .close_db = close_db, + }, + }; +} + +fn prepare(db: *anyopaque, query: [:0]const u8) PrepareError!*anyopaque { + var self: *Sqlite = @alignCast(@ptrCast(db)); + var sstmt: ?*sqlite.sqlite3_stmt = null; + if (sqlite.sqlite3_prepare_v2(self.c_db, query.ptr, @intCast(query.len), &sstmt, null) != sqlite.SQLITE_OK) { + log.err("Sqlite#prepare: sqlite3_prepare_v2: {s}", .{sqlite.sqlite3_errmsg(self.c_db)}); + return PrepareError.Failed; + } + return sstmt.?; +} + +fn step(db: *anyopaque, stmt: *anyopaque) StepError!bool { + var self: *Sqlite = @alignCast(@ptrCast(db)); + var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); + const res = sqlite.sqlite3_step(sstmt); + if (res == sqlite.SQLITE_ROW) { + return true; + } else if (res == sqlite.SQLITE_DONE) { + return false; + } else { + log.err("Sqlite#step: sqlite3_step: {s}", .{sqlite.sqlite3_errmsg(self.c_db)}); + return StepError.Failed; + } +} + +fn column_i64(db: *anyopaque, stmt: *anyopaque, idx: u31) ColumnError!?i64 { + _ = db; + var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); + const ct = sqlite.sqlite3_column_type(sstmt, idx); + if (ct == sqlite.SQLITE_NULL) { + return null; + } else if (ct == sqlite.SQLITE_INTEGER) { + return sqlite.sqlite3_column_int64(sstmt, idx); + } else { + return ColumnError.WrongType; + } +} +fn column_slice_const_u8(db: *anyopaque, stmt: *anyopaque, idx: u31) ColumnError!?[:0]const u8 { + _ = db; + var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); + const ct = sqlite.sqlite3_column_type(sstmt, idx); + if (ct == sqlite.SQLITE_NULL) { + return null; + } else if (ct == sqlite.SQLITE_TEXT) { + const value_c = sqlite.sqlite3_column_text(sstmt, idx); + return std.mem.sliceTo(value_c, 0); + } else { + return ColumnError.WrongType; + } +} + +fn close_stmt(db: *anyopaque, stmt: *anyopaque) void { + _ = db; + var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); + _ = sqlite.sqlite3_finalize(sstmt); +} + +fn close_db(db: *anyopaque) void { + var self: *Sqlite = @alignCast(@ptrCast(db)); + _ = sqlite.sqlite3_close_v2(self.c_db); + self.allocator.destroy(self); +}
\ No newline at end of file |