1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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);
}
|