diff --git a/src/network/cache/SqliteCache.zig b/src/network/cache/SqliteCache.zig index 28e0111be..eac5839e3 100644 --- a/src/network/cache/SqliteCache.zig +++ b/src/network/cache/SqliteCache.zig @@ -28,6 +28,7 @@ const CachedMetadata = Cache.CachedMetadata; const CachedResponse = Cache.CachedResponse; const Http = @import("../http.zig"); +const Blob = @import("../../storage/sqlite/Sqlite.zig").Blob; const Pool = @import("../../storage/sqlite/Pool.zig"); const Conn = @import("../../storage/sqlite/Sqlite.zig").Conn; const Migration = @import("../../storage/sqlite/Sqlite.zig").Migration; @@ -62,9 +63,8 @@ const cache_migrations: []const Migration = &.{ \\ create table header ( \\ url text not null, \\ name text not null, - \\ value text not null, + \\ value blob not null, \\ vary integer not null, - \\ primary key (url, name), \\ foreign key (url) references metadata(url) on delete cascade \\ ) strict }, @@ -149,7 +149,7 @@ fn loadMetadata(conn: Conn, arena: std.mem.Allocator, url: []const u8) !?CachedM while (try header_rows.next()) |row| { const name = try arena.dupe(u8, row.get([]const u8, 0)); - const value = try arena.dupe(u8, row.get([]const u8, 1)); + const value = try arena.dupe(u8, row.get(Blob, 1).data); const vary = row.get(bool, 2); if (std.ascii.eqlIgnoreCase(name, "content-type")) { @@ -188,7 +188,7 @@ fn loadBody(conn: Conn, arena: std.mem.Allocator, url: []const u8) ![]const u8 { ) orelse @panic("valid metadata must have a body"); defer body_entry.deinit(); - return try arena.dupe(u8, body_entry.get([]const u8, 0)); + return try arena.dupe(u8, body_entry.get(Blob, 0).data); } fn insertMetadata(conn: Conn, meta: CachedMetadata, body: []const u8) !void { @@ -209,7 +209,7 @@ fn insertMetadata(conn: Conn, meta: CachedMetadata, body: []const u8) !void { try conn.exec( "insert into body (url, data) values ($1, $2)", - .{ meta.url, body }, + .{ meta.url, Blob{ .data = body } }, ); var lower_name: [256]u8 = undefined; @@ -218,7 +218,7 @@ fn insertMetadata(conn: Conn, meta: CachedMetadata, body: []const u8) !void { const name = std.ascii.lowerString(lower_name[0..h.name.len], h.name); try conn.exec( "insert into header (url, name, value, vary) values ($1, $2, $3, false)", - .{ meta.url, name, h.value }, + .{ meta.url, name, Blob{ .data = h.value } }, ); } for (meta.vary_headers) |h| { @@ -226,7 +226,7 @@ fn insertMetadata(conn: Conn, meta: CachedMetadata, body: []const u8) !void { const name = std.ascii.lowerString(lower_name[0..h.name.len], h.name); try conn.exec( "insert into header (url, name, value, vary) values ($1, $2, $3, true)", - .{ meta.url, name, h.value }, + .{ meta.url, name, Blob{ .data = h.value } }, ); } } @@ -255,7 +255,7 @@ fn updateMetadata(conn: Conn, meta: CachedMetadata) !void { const name = std.ascii.lowerString(lower_name[0..h.name.len], h.name); try conn.exec( "insert into header (url, name, value, vary) values ($1, $2, $3, false)", - .{ meta.url, name, h.value }, + .{ meta.url, name, Blob{ .data = h.value } }, ); } } diff --git a/src/storage/sqlite/Sqlite.zig b/src/storage/sqlite/Sqlite.zig index f06d5f63b..5a52e8e6e 100644 --- a/src/storage/sqlite/Sqlite.zig +++ b/src/storage/sqlite/Sqlite.zig @@ -27,6 +27,8 @@ const Allocator = std.mem.Allocator; const Sqlite = @This(); +pub const Blob = struct { data: []const u8 }; + pub const Migration = union(enum) { sql: [:0]const u8, func: struct { @@ -238,6 +240,14 @@ const Statement = struct { const data = c.sqlite3_column_text(stmt, @intCast(index)); return @as([*c]const u8, @ptrCast(data))[0..@intCast(len) :0]; }, + Blob => { + const len = c.sqlite3_column_bytes(stmt, @intCast(index)); + if (len == 0) { + return Blob{ .data = &.{} }; + } + const data = c.sqlite3_column_blob(stmt, @intCast(index)); + return Blob{ .data = @as([*c]const u8, @ptrCast(data))[0..@intCast(len)] }; + }, else => @compileError("unsupported column type: " ++ @typeName(T)), }; } @@ -286,6 +296,13 @@ const Statement = struct { rc = c.sqlite3_bind_int64(stmt, bind_index, @intCast(0)); } }, + .@"struct" => { + if (T == Blob) { + rc = c.sqlite3_bind_blob(stmt, bind_index, value.data.ptr, @intCast(value.data.len), c.SQLITE_STATIC); + } else { + bindError(T); + } + }, .pointer => |ptr| { switch (ptr.size) { .one => switch (@typeInfo(ptr.child)) {