Bind query parameters
This commit is contained in:
parent
81df6d8461
commit
3365ce7a11
2 changed files with 85 additions and 3 deletions
|
@ -84,12 +84,94 @@ pub const Engine = struct {
|
|||
sql: []const u8,
|
||||
args: []const SqlValue,
|
||||
opts: QueryOptions,
|
||||
alloc: Allocator,
|
||||
_: Allocator,
|
||||
) ExecError!Results {
|
||||
const self: *Engine = @ptrCast(*Engine, @alignCast(@alignOf(Engine), ctx));
|
||||
_ = .{ self, sql, args, opts, alloc };
|
||||
|
||||
var stmt: ?*c.sqlite3_stmt = undefined;
|
||||
switch (c.sqlite3_prepare_v2(self.conn, sql.ptr, @intCast(c_int, sql.len), &stmt, null)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => |err| return handleUnexpectedError(self.conn, err, sql),
|
||||
}
|
||||
errdefer switch (c.sqlite3_finalize(stmt)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => |err| {
|
||||
handleUnexpectedError(self.conn, err, sql) catch {};
|
||||
},
|
||||
};
|
||||
|
||||
if (args.len != 0) {
|
||||
for (args) |arg, i| {
|
||||
const buf_size = 21; // ceil(log10(2^64)) + 1
|
||||
var name_buf: [buf_size]u8 = undefined;
|
||||
const name = std.fmt.bufPrintZ(&name_buf, "{}", .{i}) catch unreachable;
|
||||
|
||||
const db_idx = c.sqlite3_bind_parameter_index(stmt.?, name.ptr);
|
||||
if (db_idx != 0)
|
||||
try self.bindArgument(stmt.?, @intCast(u15, db_idx), arg)
|
||||
else if (!opts.ignore_unused_arguments)
|
||||
return error.UnusedArgument;
|
||||
}
|
||||
}
|
||||
|
||||
@panic("unimplemented");
|
||||
}
|
||||
|
||||
fn bindArgument(self: *Engine, stmt: *c.sqlite3_stmt, idx: u15, val: SqlValue) !void {
|
||||
return switch (val) {
|
||||
.int => |v| self.bindInt(stmt, idx, i64, v),
|
||||
.uint => |v| self.bindInt(stmt, idx, u64, v),
|
||||
.str => |str| {
|
||||
const len = std.math.cast(c_int, str.len) orelse {
|
||||
std.log.err("SQLite: string len {} too large", .{str.len});
|
||||
return error.BindException;
|
||||
};
|
||||
|
||||
switch (c.sqlite3_bind_text(stmt, idx, str.ptr, len, c.SQLITE_TRANSIENT)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => |result| {
|
||||
std.log.err("SQLite: Unable to bind string to index {}", .{idx});
|
||||
std.log.debug("SQLite: {s}", .{str});
|
||||
return handleUnexpectedError(self.conn, result, null);
|
||||
},
|
||||
}
|
||||
},
|
||||
.float => |v| {
|
||||
switch (c.sqlite3_bind_double(stmt, idx, v)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => |result| {
|
||||
std.log.err("SQLite: Unable to bind float to index {}", .{idx});
|
||||
std.log.debug("SQLite: {}", .{v});
|
||||
return handleUnexpectedError(self.conn, result, null);
|
||||
},
|
||||
}
|
||||
},
|
||||
.@"null" => {
|
||||
switch (c.sqlite3_bind_null(stmt, idx)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => |result| {
|
||||
std.log.err("SQLite: Unable to bind NULL to index {}", .{idx});
|
||||
return handleUnexpectedError(self.conn, result, null);
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn bindInt(self: *Engine, stmt: *c.sqlite3_stmt, idx: u15, comptime T: type, val: T) !void {
|
||||
const v = std.math.cast(i64, val) orelse {
|
||||
std.log.err("SQLite: integer {} does not fit within i64", .{val});
|
||||
return error.BindException;
|
||||
};
|
||||
switch (c.sqlite3_bind_int64(stmt, idx, v)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => |result| {
|
||||
std.log.err("SQLite: Unable to bind int to index {}", .{idx});
|
||||
std.log.debug("SQLite: {}", .{v});
|
||||
return handleUnexpectedError(self.conn, result, null);
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn getCharPos(text: []const u8, offset: c_int) struct { row: usize, col: usize } {
|
||||
|
|
|
@ -107,5 +107,5 @@ test "test" {
|
|||
|
||||
const db = engine.db();
|
||||
|
||||
_ = db;
|
||||
_ = try db.vtable.exec(db.ptr, "CREATE TABLE foo(bar INT PRIMARY KEY);", &.{}, .{}, std.testing.allocator);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue