aboutsummaryrefslogtreecommitdiff
path: root/src/sqlite.zig
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-09-03 20:32:51 +0100
committerMartin Ashby <martin@ashbysoft.com>2023-09-03 20:32:51 +0100
commit2c4ac3819b8c42de1410fd524c2c9d08d937ec70 (patch)
tree570d63ee4c92d69c96c5d21bfb2be3adb35376a6 /src/sqlite.zig
downloadsql-zig-main.tar.gz
sql-zig-main.tar.bz2
sql-zig-main.tar.xz
sql-zig-main.zip
InitialHEADmain
Diffstat (limited to 'src/sqlite.zig')
-rw-r--r--src/sqlite.zig101
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