Add open/close methods

This commit is contained in:
jaina heartles 2023-07-06 01:29:13 -07:00
parent ed515c059d
commit 81df6d8461
2 changed files with 95 additions and 12 deletions

View file

@ -1,7 +1,7 @@
const common = @import("../lib.zig");
const std = @import("std");
const c = @cImport({
//@cInclude("sqlite3.h");
@cInclude("sqlite3.h");
});
const QueryOptions = common.QueryOptions;
@ -12,22 +12,71 @@ const Results = common.Results;
const Allocator = std.mem.Allocator;
pub const Engine = struct {
//db: *c.sqlite3,
dummy: usize = 0,
conn: *c.sqlite3,
pub fn open(path: [:0]const u8) !Engine {
return openInternal(path, false);
}
pub fn openUri(path: [:0]const u8) !Engine {
return openInternal(path, true);
}
fn openInternal(path: [:0]const u8, is_uri: bool) !Engine {
const flags = c.SQLITE_OPEN_READWRITE | c.SQLITE_OPEN_CREATE | c.SQLITE_OPEN_EXRESCODE | if (is_uri) c.SQLITE_OPEN_URI else 0;
var conn: ?*c.sqlite3 = null;
switch (c.sqlite3_open_v2(@ptrCast([*c]const u8, path), &conn, flags, null)) {
c.SQLITE_OK => {},
else => |code| {
if (conn == null) {
// this path should only be hit if out of memory, but log it anyways
std.log.err(
"Unable to open SQLite DB \"{s}\". Error: {?s} ({})",
.{ path, c.sqlite3_errstr(code), code },
);
return error.BadConnection;
}
const ext_code = c.sqlite3_extended_errcode(conn);
std.log.err(
\\Unable to open SQLite DB "{s}". Error: {?s} ({})
\\Details: {?s}
,
.{ path, c.sqlite3_errstr(ext_code), ext_code, c.sqlite3_errmsg(conn) },
);
return error.Unexpected;
},
}
return Engine{
.conn = conn.?,
};
}
pub fn db(self: *Engine) common.Db {
return .{
.ptr = self,
.vtable = &.{
.close = Engine.close,
.exec = Engine.exec,
},
};
}
fn close(ctx: *anyopaque) void {
const self: *Engine = @ptrCast(*Engine, @alignCast(@alignOf(Engine), ctx));
_ = self;
pub fn close(self: *Engine) void {
switch (c.sqlite3_close(self.conn)) {
c.SQLITE_OK => {},
c.SQLITE_BUSY => {
std.log.err("SQLite DB could not be closed as it is busy.\n{s}", .{c.sqlite3_errmsg(self.conn)});
},
else => |err| {
std.log.err("Could not close SQLite DB", .{});
handleUnexpectedError(self.conn, err, null) catch {};
},
}
}
fn exec(
@ -42,3 +91,39 @@ pub const Engine = struct {
@panic("unimplemented");
}
};
fn getCharPos(text: []const u8, offset: c_int) struct { row: usize, col: usize } {
var row: usize = 0;
var col: usize = 0;
var i: usize = 0;
if (offset > text.len) return .{ .row = 0, .col = 0 };
while (i != offset) : (i += 1) {
if (text[i] == '\n') {
row += 1;
col = 0;
} else {
col += 1;
}
}
return .{ .row = row, .col = col };
}
fn handleUnexpectedError(db: *c.sqlite3, code: c_int, sql_text: ?[]const u8) error{Unexpected} {
std.log.err("Unexpected error in SQLite engine: {s} ({})", .{ c.sqlite3_errstr(code), code });
std.log.debug("Additional details:", .{});
std.log.debug("{?s}", .{c.sqlite3_errmsg(db)});
if (sql_text) |sql| {
const byte_offset = c.sqlite3_error_offset(db);
if (byte_offset >= 0) {
const pos = getCharPos(sql, byte_offset);
std.log.debug("Failed at char ({}:{}) of SQL:\n{s}", .{ pos.row, pos.col, sql });
}
}
std.log.debug("{?}", .{@errorReturnTrace()});
return error.Unexpected;
}

View file

@ -48,9 +48,6 @@ pub const ExecError = error{
pub const Db = struct {
pub const VTable = struct {
/// Closes the database connection
close: *const fn (ctx: *anyopaque) void,
/// Executes a SQL query.
/// All memory allocated with this allocator must be freed before this function returns.
exec: *const fn (ctx: *anyopaque, sql: []const u8, args: []const SqlValue, opt: QueryOptions, allocator: Allocator) ExecError!Results,
@ -104,8 +101,9 @@ pub const Row = struct {
};
test "test" {
const backend = @import("./engines/sqlite2.zig");
var engine: backend.Engine = undefined;
const backend = @import("./engines/sqlite.zig");
var engine = try backend.Engine.open(":memory:");
defer engine.close();
const db = engine.db();