sqlite.zig (3475B)
1 const std = @import("std"); 2 const sqlite = @cImport({ 3 @cInclude("sqlite3.h"); 4 }); 5 const Db = @import("main.zig"); 6 const OpenError = Db.OpenError; 7 const PrepareError = Db.PrepareError; 8 const StepError = Db.StepError; 9 const ColumnError = Db.ColumnError; 10 const log = @import("log.zig").scoped_log_t(.sqlite); 11 12 //// Sqlite implementation 13 pub const Sqlite = @This(); 14 15 allocator: std.mem.Allocator, 16 c_db: *sqlite.sqlite3, 17 18 pub fn open(allocator: std.mem.Allocator, filename: [:0]const u8) OpenError!Db { 19 var db: ?*sqlite.sqlite3 = null; 20 const oo = sqlite.SQLITE_OPEN_CREATE | sqlite.SQLITE_OPEN_READWRITE | sqlite.SQLITE_OPEN_FULLMUTEX; 21 if (sqlite.sqlite3_open_v2(filename.ptr, &db, oo, null) != sqlite.SQLITE_OK) { 22 log.err("Sqlite#open: sqlite3_open_v2 error {s}", .{sqlite.sqlite3_errmsg(db)}); 23 return OpenError.Failed; 24 } 25 var sqlite_db = try allocator.create(Sqlite); 26 sqlite_db.allocator = allocator; 27 sqlite_db.c_db = db.?; 28 return Db{ 29 .ptr = sqlite_db, 30 .vtable = .{ 31 .prepare = prepare, 32 .step = step, 33 .column_i64 = column_i64, 34 .column_slice_const_u8 = column_slice_const_u8, 35 .close_stmt = close_stmt, 36 .close_db = close_db, 37 }, 38 }; 39 } 40 41 fn prepare(db: *anyopaque, query: [:0]const u8) PrepareError!*anyopaque { 42 var self: *Sqlite = @alignCast(@ptrCast(db)); 43 var sstmt: ?*sqlite.sqlite3_stmt = null; 44 if (sqlite.sqlite3_prepare_v2(self.c_db, query.ptr, @intCast(query.len), &sstmt, null) != sqlite.SQLITE_OK) { 45 log.err("Sqlite#prepare: sqlite3_prepare_v2: {s}", .{sqlite.sqlite3_errmsg(self.c_db)}); 46 return PrepareError.Failed; 47 } 48 return sstmt.?; 49 } 50 51 fn step(db: *anyopaque, stmt: *anyopaque) StepError!bool { 52 var self: *Sqlite = @alignCast(@ptrCast(db)); 53 var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); 54 const res = sqlite.sqlite3_step(sstmt); 55 if (res == sqlite.SQLITE_ROW) { 56 return true; 57 } else if (res == sqlite.SQLITE_DONE) { 58 return false; 59 } else { 60 log.err("Sqlite#step: sqlite3_step: {s}", .{sqlite.sqlite3_errmsg(self.c_db)}); 61 return StepError.Failed; 62 } 63 } 64 65 fn column_i64(db: *anyopaque, stmt: *anyopaque, idx: u31) ColumnError!?i64 { 66 _ = db; 67 var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); 68 const ct = sqlite.sqlite3_column_type(sstmt, idx); 69 if (ct == sqlite.SQLITE_NULL) { 70 return null; 71 } else if (ct == sqlite.SQLITE_INTEGER) { 72 return sqlite.sqlite3_column_int64(sstmt, idx); 73 } else { 74 return ColumnError.WrongType; 75 } 76 } 77 fn column_slice_const_u8(db: *anyopaque, stmt: *anyopaque, idx: u31) ColumnError!?[:0]const u8 { 78 _ = db; 79 var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); 80 const ct = sqlite.sqlite3_column_type(sstmt, idx); 81 if (ct == sqlite.SQLITE_NULL) { 82 return null; 83 } else if (ct == sqlite.SQLITE_TEXT) { 84 const value_c = sqlite.sqlite3_column_text(sstmt, idx); 85 return std.mem.sliceTo(value_c, 0); 86 } else { 87 return ColumnError.WrongType; 88 } 89 } 90 91 fn close_stmt(db: *anyopaque, stmt: *anyopaque) void { 92 _ = db; 93 var sstmt: *sqlite.sqlite3_stmt = @alignCast(@ptrCast(stmt)); 94 _ = sqlite.sqlite3_finalize(sstmt); 95 } 96 97 fn close_db(db: *anyopaque) void { 98 var self: *Sqlite = @alignCast(@ptrCast(db)); 99 _ = sqlite.sqlite3_close_v2(self.c_db); 100 self.allocator.destroy(self); 101 }