Add open/close methods
This commit is contained in:
parent
ed515c059d
commit
81df6d8461
2 changed files with 95 additions and 12 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue