summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sqlite.zig125
1 files changed, 73 insertions, 52 deletions
diff --git a/sqlite.zig b/sqlite.zig
index 97241e9..c9b0640 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -276,7 +276,7 @@ fn getDetailedErrorFromResultCode(code: c_int) DetailedError {
276 .code = @intCast(usize, code), 276 .code = @intCast(usize, code),
277 .message = blk: { 277 .message = blk: {
278 const msg = c.sqlite3_errstr(code); 278 const msg = c.sqlite3_errstr(code);
279 break :blk mem.spanZ(msg); 279 break :blk mem.sliceTo(msg, 0);
280 }, 280 },
281 }; 281 };
282} 282}
@@ -286,7 +286,7 @@ fn getLastDetailedErrorFromDb(db: *c.sqlite3) DetailedError {
286 .code = @intCast(usize, c.sqlite3_extended_errcode(db)), 286 .code = @intCast(usize, c.sqlite3_extended_errcode(db)),
287 .message = blk: { 287 .message = blk: {
288 const msg = c.sqlite3_errmsg(db); 288 const msg = c.sqlite3_errmsg(db);
289 break :blk mem.spanZ(msg); 289 break :blk mem.sliceTo(msg, 0);
290 }, 290 },
291 }; 291 };
292} 292}
@@ -422,7 +422,7 @@ pub const Db = struct {
422 /// 422 ///
423 /// const journal_mode = try db.pragma([]const u8, allocator, .{}, "journal_mode", null); 423 /// const journal_mode = try db.pragma([]const u8, allocator, .{}, "journal_mode", null);
424 /// 424 ///
425 pub fn pragmaAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, comptime name: []const u8, comptime arg: ?[]const u8) !?Type { 425 pub fn pragmaAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, options: QueryOptions, comptime name: []const u8, comptime arg: ?[]const u8) !?Type {
426 comptime var query = getPragmaQuery(name, arg); 426 comptime var query = getPragmaQuery(name, arg);
427 427
428 var stmt = try self.prepare(query); 428 var stmt = try self.prepare(query);
@@ -482,14 +482,14 @@ pub const Db = struct {
482 } 482 }
483 483
484 /// oneAlloc is like `one` but can allocate memory. 484 /// oneAlloc is like `one` but can allocate memory.
485 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, comptime query: []const u8, options: QueryOptions, values: anytype) !?Type { 485 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, comptime query: []const u8, options: QueryOptions, values: anytype) !?Type {
486 var stmt = try self.prepareWithDiags(query, options); 486 var stmt = try self.prepareWithDiags(query, options);
487 defer stmt.deinit(); 487 defer stmt.deinit();
488 return try stmt.oneAlloc(Type, allocator, options, values); 488 return try stmt.oneAlloc(Type, allocator, options, values);
489 } 489 }
490 490
491 /// oneDynamicAlloc is like `oneDynamic` but can allocate memory. 491 /// oneDynamicAlloc is like `oneDynamic` but can allocate memory.
492 pub fn oneDynamicAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, query: []const u8, options: QueryOptions, values: anytype) !?Type { 492 pub fn oneDynamicAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, query: []const u8, options: QueryOptions, values: anytype) !?Type {
493 var stmt = try self.prepareDynamicWithDiags(query, options); 493 var stmt = try self.prepareDynamicWithDiags(query, options);
494 defer stmt.deinit(); 494 defer stmt.deinit();
495 return try stmt.oneAlloc(Type, allocator, options, values); 495 return try stmt.oneAlloc(Type, allocator, options, values);
@@ -662,9 +662,10 @@ pub const Savepoint = struct {
662 662
663 var buffer: [256]u8 = undefined; 663 var buffer: [256]u8 = undefined;
664 var fba = std.heap.FixedBufferAllocator.init(&buffer); 664 var fba = std.heap.FixedBufferAllocator.init(&buffer);
665 var allocator = fba.allocator();
665 666
666 const commit_query = try std.fmt.allocPrint(&fba.allocator, "RELEASE SAVEPOINT {s}", .{name}); 667 const commit_query = try std.fmt.allocPrint(allocator, "RELEASE SAVEPOINT {s}", .{name});
667 const rollback_query = try std.fmt.allocPrint(&fba.allocator, "ROLLBACK TRANSACTION TO SAVEPOINT {s}", .{name}); 668 const rollback_query = try std.fmt.allocPrint(allocator, "ROLLBACK TRANSACTION TO SAVEPOINT {s}", .{name});
668 669
669 var res = Self{ 670 var res = Self{
670 .db = db, 671 .db = db,
@@ -674,7 +675,7 @@ pub const Savepoint = struct {
674 }; 675 };
675 676
676 try res.db.execDynamic( 677 try res.db.execDynamic(
677 try std.fmt.allocPrint(&fba.allocator, "SAVEPOINT {s}", .{name}), 678 try std.fmt.allocPrint(allocator, "SAVEPOINT {s}", .{name}),
678 .{}, 679 .{},
679 .{}, 680 .{},
680 ); 681 );
@@ -802,7 +803,7 @@ pub fn Iterator(comptime Type: type) type {
802 } 803 }
803 804
804 // nextAlloc is like `next` but can allocate memory. 805 // nextAlloc is like `next` but can allocate memory.
805 pub fn nextAlloc(self: *Self, allocator: *mem.Allocator, options: QueryOptions) !?Type { 806 pub fn nextAlloc(self: *Self, allocator: mem.Allocator, options: QueryOptions) !?Type {
806 var dummy_diags = Diagnostics{}; 807 var dummy_diags = Diagnostics{};
807 var diags = options.diags orelse &dummy_diags; 808 var diags = options.diags orelse &dummy_diags;
808 809
@@ -952,7 +953,7 @@ pub fn Iterator(comptime Type: type) type {
952 }; 953 };
953 954
954 // dupeWithSentinel is like dupe/dupeZ but allows for any sentinel value. 955 // dupeWithSentinel is like dupe/dupeZ but allows for any sentinel value.
955 fn dupeWithSentinel(comptime SliceType: type, allocator: *mem.Allocator, data: []const u8) !SliceType { 956 fn dupeWithSentinel(comptime SliceType: type, allocator: mem.Allocator, data: []const u8) !SliceType {
956 switch (@typeInfo(SliceType)) { 957 switch (@typeInfo(SliceType)) {
957 .Pointer => |ptr_info| { 958 .Pointer => |ptr_info| {
958 if (ptr_info.sentinel) |sentinel| { 959 if (ptr_info.sentinel) |sentinel| {
@@ -979,7 +980,7 @@ pub fn Iterator(comptime Type: type) type {
979 // When using .Text you can only read into either []const u8, []u8 or Text. 980 // When using .Text you can only read into either []const u8, []u8 or Text.
980 // 981 //
981 // The options must contain an `allocator` field which will be used to create a copy of the data. 982 // The options must contain an `allocator` field which will be used to create a copy of the data.
982 fn readBytes(self: *Self, comptime BytesType: type, allocator: *mem.Allocator, _i: usize, comptime mode: ReadBytesMode) !BytesType { 983 fn readBytes(self: *Self, comptime BytesType: type, allocator: mem.Allocator, _i: usize, comptime mode: ReadBytesMode) !BytesType {
983 const i = @intCast(c_int, _i); 984 const i = @intCast(c_int, _i);
984 985
985 switch (mode) { 986 switch (mode) {
@@ -1498,7 +1499,7 @@ pub const DynamicStatement = struct {
1498 /// 1499 ///
1499 /// Possible errors: 1500 /// Possible errors:
1500 /// - SQLiteError.SQLiteNotFound if some fields not found 1501 /// - SQLiteError.SQLiteNotFound if some fields not found
1501 pub fn iteratorAlloc(self: *Self, comptime Type: type, allocator: *std.mem.Allocator, values: anytype) !Iterator(Type) { 1502 pub fn iteratorAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, values: anytype) !Iterator(Type) {
1502 try self.bind(.{ .allocator = allocator }, values); 1503 try self.bind(.{ .allocator = allocator }, values);
1503 1504
1504 var res: Iterator(Type) = undefined; 1505 var res: Iterator(Type) = undefined;
@@ -1541,7 +1542,7 @@ pub const DynamicStatement = struct {
1541 } 1542 }
1542 1543
1543 /// oneAlloc is like `one` but can allocate memory. 1544 /// oneAlloc is like `one` but can allocate memory.
1544 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, values: anytype) !?Type { 1545 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, options: QueryOptions, values: anytype) !?Type {
1545 var iter = try self.iteratorAlloc(Type, allocator, values); 1546 var iter = try self.iteratorAlloc(Type, allocator, values);
1546 1547
1547 const row = (try iter.nextAlloc(allocator, options)) orelse return null; 1548 const row = (try iter.nextAlloc(allocator, options)) orelse return null;
@@ -1574,7 +1575,7 @@ pub const DynamicStatement = struct {
1574 /// in the input query string. 1575 /// in the input query string.
1575 /// 1576 ///
1576 /// Note that this allocates all rows into a single slice: if you read a lot of data this can use a lot of memory. 1577 /// Note that this allocates all rows into a single slice: if you read a lot of data this can use a lot of memory.
1577 pub fn all(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, values: anytype) ![]Type { 1578 pub fn all(self: *Self, comptime Type: type, allocator: mem.Allocator, options: QueryOptions, values: anytype) ![]Type {
1578 var iter = try self.iterator(Type, values); 1579 var iter = try self.iterator(Type, values);
1579 1580
1580 var rows = std.ArrayList(Type).init(allocator); 1581 var rows = std.ArrayList(Type).init(allocator);
@@ -1700,7 +1701,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1700 } 1701 }
1701 1702
1702 /// execAlloc is like `exec` but can allocate memory. 1703 /// execAlloc is like `exec` but can allocate memory.
1703 pub fn execAlloc(self: *Self, allocator: *std.mem.Allocator, options: QueryOptions, values: anytype) !void { 1704 pub fn execAlloc(self: *Self, allocator: mem.Allocator, options: QueryOptions, values: anytype) !void {
1704 try self.bind(.{ .allocator = allocator }, values); 1705 try self.bind(.{ .allocator = allocator }, values);
1705 1706
1706 var dummy_diags = Diagnostics{}; 1707 var dummy_diags = Diagnostics{};
@@ -1768,7 +1769,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1768 } 1769 }
1769 1770
1770 /// iteratorAlloc is like `iterator` but can allocate memory. 1771 /// iteratorAlloc is like `iterator` but can allocate memory.
1771 pub fn iteratorAlloc(self: *Self, comptime Type: type, allocator: *std.mem.Allocator, values: anytype) !Iterator(Type) { 1772 pub fn iteratorAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, values: anytype) !Iterator(Type) {
1772 try self.bind(.{ .allocator = allocator }, values); 1773 try self.bind(.{ .allocator = allocator }, values);
1773 1774
1774 var res: Iterator(Type) = undefined; 1775 var res: Iterator(Type) = undefined;
@@ -1811,7 +1812,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1811 } 1812 }
1812 1813
1813 /// oneAlloc is like `one` but can allocate memory. 1814 /// oneAlloc is like `one` but can allocate memory.
1814 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, values: anytype) !?Type { 1815 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: mem.Allocator, options: QueryOptions, values: anytype) !?Type {
1815 var iter = try self.iteratorAlloc(Type, allocator, values); 1816 var iter = try self.iteratorAlloc(Type, allocator, values);
1816 1817
1817 const row = (try iter.nextAlloc(allocator, options)) orelse return null; 1818 const row = (try iter.nextAlloc(allocator, options)) orelse return null;
@@ -1844,7 +1845,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1844 /// in the input query string. 1845 /// in the input query string.
1845 /// 1846 ///
1846 /// Note that this allocates all rows into a single slice: if you read a lot of data this can use a lot of memory. 1847 /// Note that this allocates all rows into a single slice: if you read a lot of data this can use a lot of memory.
1847 pub fn all(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, values: anytype) ![]Type { 1848 pub fn all(self: *Self, comptime Type: type, allocator: mem.Allocator, options: QueryOptions, values: anytype) ![]Type {
1848 var iter = try self.iteratorAlloc(Type, allocator, values); 1849 var iter = try self.iteratorAlloc(Type, allocator, values);
1849 1850
1850 var rows = std.ArrayList(Type).init(allocator); 1851 var rows = std.ArrayList(Type).init(allocator);
@@ -1935,6 +1936,7 @@ test "sqlite: db init" {
1935test "sqlite: db pragma" { 1936test "sqlite: db pragma" {
1936 var arena = std.heap.ArenaAllocator.init(testing.allocator); 1937 var arena = std.heap.ArenaAllocator.init(testing.allocator);
1937 defer arena.deinit(); 1938 defer arena.deinit();
1939 var allocator = arena.allocator();
1938 1940
1939 var db = try getTestDb(); 1941 var db = try getTestDb();
1940 1942
@@ -1946,11 +1948,11 @@ test "sqlite: db pragma" {
1946 { 1948 {
1947 const journal_mode = try db.pragma([128:0]u8, .{}, "journal_mode", "wal"); 1949 const journal_mode = try db.pragma([128:0]u8, .{}, "journal_mode", "wal");
1948 try testing.expect(journal_mode != null); 1950 try testing.expect(journal_mode != null);
1949 try testing.expectEqualStrings("memory", mem.spanZ(&journal_mode.?)); 1951 try testing.expectEqualStrings("memory", mem.sliceTo(&journal_mode.?, 0));
1950 } 1952 }
1951 1953
1952 { 1954 {
1953 const journal_mode = try db.pragmaAlloc([]const u8, &arena.allocator, .{}, "journal_mode", "wal"); 1955 const journal_mode = try db.pragmaAlloc([]const u8, allocator, .{}, "journal_mode", "wal");
1954 try testing.expect(journal_mode != null); 1956 try testing.expect(journal_mode != null);
1955 try testing.expectEqualStrings("memory", journal_mode.?); 1957 try testing.expectEqualStrings("memory", journal_mode.?);
1956 } 1958 }
@@ -1958,11 +1960,11 @@ test "sqlite: db pragma" {
1958 { 1960 {
1959 const journal_mode = try db.pragma([128:0]u8, .{}, "journal_mode", "wal"); 1961 const journal_mode = try db.pragma([128:0]u8, .{}, "journal_mode", "wal");
1960 try testing.expect(journal_mode != null); 1962 try testing.expect(journal_mode != null);
1961 try testing.expectEqualStrings("wal", mem.spanZ(&journal_mode.?)); 1963 try testing.expectEqualStrings("wal", mem.sliceTo(&journal_mode.?, 0));
1962 } 1964 }
1963 1965
1964 { 1966 {
1965 const journal_mode = try db.pragmaAlloc([]const u8, &arena.allocator, .{}, "journal_mode", "wal"); 1967 const journal_mode = try db.pragmaAlloc([]const u8, allocator, .{}, "journal_mode", "wal");
1966 try testing.expect(journal_mode != null); 1968 try testing.expect(journal_mode != null);
1967 try testing.expectEqualStrings("wal", journal_mode.?); 1969 try testing.expectEqualStrings("wal", journal_mode.?);
1968 } 1970 }
@@ -2034,6 +2036,7 @@ test "sqlite: statement execDynamic" {
2034test "sqlite: read a single user into a struct" { 2036test "sqlite: read a single user into a struct" {
2035 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2037 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2036 defer arena.deinit(); 2038 defer arena.deinit();
2039 var allocator = arena.allocator();
2037 2040
2038 var db = try getTestDb(); 2041 var db = try getTestDb();
2039 try addTestData(&db); 2042 try addTestData(&db);
@@ -2041,7 +2044,7 @@ test "sqlite: read a single user into a struct" {
2041 var stmt = try db.prepare("SELECT * FROM user WHERE id = ?{usize}"); 2044 var stmt = try db.prepare("SELECT * FROM user WHERE id = ?{usize}");
2042 defer stmt.deinit(); 2045 defer stmt.deinit();
2043 2046
2044 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{ 2047 var rows = try stmt.all(TestUser, allocator, .{}, .{
2045 .id = @as(usize, 20), 2048 .id = @as(usize, 20),
2046 }); 2049 });
2047 for (rows) |row| { 2050 for (rows) |row| {
@@ -2066,7 +2069,7 @@ test "sqlite: read a single user into a struct" {
2066 2069
2067 const exp = test_users[0]; 2070 const exp = test_users[0];
2068 try testing.expectEqual(exp.id, row.?.id); 2071 try testing.expectEqual(exp.id, row.?.id);
2069 try testing.expectEqualStrings(exp.name, mem.spanZ(&row.?.name)); 2072 try testing.expectEqualStrings(exp.name, mem.sliceTo(&row.?.name, 0));
2070 try testing.expectEqual(exp.age, row.?.age); 2073 try testing.expectEqual(exp.age, row.?.age);
2071 } 2074 }
2072 2075
@@ -2078,7 +2081,7 @@ test "sqlite: read a single user into a struct" {
2078 id: usize, 2081 id: usize,
2079 age: usize, 2082 age: usize,
2080 }, 2083 },
2081 &arena.allocator, 2084 allocator,
2082 "SELECT name, id, age FROM user WHERE id = ?{usize}", 2085 "SELECT name, id, age FROM user WHERE id = ?{usize}",
2083 .{}, 2086 .{},
2084 .{@as(usize, 20)}, 2087 .{@as(usize, 20)},
@@ -2095,6 +2098,7 @@ test "sqlite: read a single user into a struct" {
2095test "sqlite: read all users into a struct" { 2098test "sqlite: read all users into a struct" {
2096 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2099 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2097 defer arena.deinit(); 2100 defer arena.deinit();
2101 var allocator = arena.allocator();
2098 2102
2099 var db = try getTestDb(); 2103 var db = try getTestDb();
2100 try addTestData(&db); 2104 try addTestData(&db);
@@ -2102,7 +2106,7 @@ test "sqlite: read all users into a struct" {
2102 var stmt = try db.prepare("SELECT * FROM user"); 2106 var stmt = try db.prepare("SELECT * FROM user");
2103 defer stmt.deinit(); 2107 defer stmt.deinit();
2104 2108
2105 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{}); 2109 var rows = try stmt.all(TestUser, allocator, .{}, .{});
2106 try testing.expectEqual(@as(usize, 3), rows.len); 2110 try testing.expectEqual(@as(usize, 3), rows.len);
2107 for (rows) |row, i| { 2111 for (rows) |row, i| {
2108 const exp = test_users[i]; 2112 const exp = test_users[i];
@@ -2116,6 +2120,7 @@ test "sqlite: read all users into a struct" {
2116test "sqlite: read in an anonymous struct" { 2120test "sqlite: read in an anonymous struct" {
2117 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2121 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2118 defer arena.deinit(); 2122 defer arena.deinit();
2123 var allocator = arena.allocator();
2119 2124
2120 var db = try getTestDb(); 2125 var db = try getTestDb();
2121 try addTestData(&db); 2126 try addTestData(&db);
@@ -2132,7 +2137,7 @@ test "sqlite: read in an anonymous struct" {
2132 is_id: bool, 2137 is_id: bool,
2133 weight: f64, 2138 weight: f64,
2134 }, 2139 },
2135 &arena.allocator, 2140 allocator,
2136 .{}, 2141 .{},
2137 .{ .id = @as(usize, 20) }, 2142 .{ .id = @as(usize, 20) },
2138 ); 2143 );
@@ -2141,7 +2146,7 @@ test "sqlite: read in an anonymous struct" {
2141 const exp = test_users[0]; 2146 const exp = test_users[0];
2142 try testing.expectEqual(exp.id, row.?.id); 2147 try testing.expectEqual(exp.id, row.?.id);
2143 try testing.expectEqualStrings(exp.name, row.?.name); 2148 try testing.expectEqualStrings(exp.name, row.?.name);
2144 try testing.expectEqualStrings(exp.name, mem.spanZ(&row.?.name_2)); 2149 try testing.expectEqualStrings(exp.name, mem.sliceTo(&row.?.name_2, 0xAD));
2145 try testing.expectEqual(exp.age, row.?.age); 2150 try testing.expectEqual(exp.age, row.?.age);
2146 try testing.expect(row.?.is_id); 2151 try testing.expect(row.?.is_id);
2147 try testing.expectEqual(exp.weight, @floatCast(f32, row.?.weight)); 2152 try testing.expectEqual(exp.weight, @floatCast(f32, row.?.weight));
@@ -2150,6 +2155,7 @@ test "sqlite: read in an anonymous struct" {
2150test "sqlite: read in a Text struct" { 2155test "sqlite: read in a Text struct" {
2151 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2156 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2152 defer arena.deinit(); 2157 defer arena.deinit();
2158 var allocator = arena.allocator();
2153 2159
2154 var db = try getTestDb(); 2160 var db = try getTestDb();
2155 try addTestData(&db); 2161 try addTestData(&db);
@@ -2163,7 +2169,7 @@ test "sqlite: read in a Text struct" {
2163 id: usize, 2169 id: usize,
2164 age: usize, 2170 age: usize,
2165 }, 2171 },
2166 &arena.allocator, 2172 allocator,
2167 .{}, 2173 .{},
2168 .{@as(usize, 20)}, 2174 .{@as(usize, 20)},
2169 ); 2175 );
@@ -2178,6 +2184,7 @@ test "sqlite: read in a Text struct" {
2178test "sqlite: read a single text value" { 2184test "sqlite: read a single text value" {
2179 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2185 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2180 defer arena.deinit(); 2186 defer arena.deinit();
2187 var allocator = arena.allocator();
2181 2188
2182 var db = try getTestDb(); 2189 var db = try getTestDb();
2183 try addTestData(&db); 2190 try addTestData(&db);
@@ -2193,6 +2200,7 @@ test "sqlite: read a single text value" {
2193 // Array 2200 // Array
2194 [8:0]u8, 2201 [8:0]u8,
2195 [8:0xAD]u8, 2202 [8:0xAD]u8,
2203 [7]u8,
2196 // Specific text or blob 2204 // Specific text or blob
2197 Text, 2205 Text,
2198 Blob, 2206 Blob,
@@ -2204,7 +2212,7 @@ test "sqlite: read a single text value" {
2204 var stmt: StatementType(.{}, query) = try db.prepare(query); 2212 var stmt: StatementType(.{}, query) = try db.prepare(query);
2205 defer stmt.deinit(); 2213 defer stmt.deinit();
2206 2214
2207 const name = try stmt.oneAlloc(typ, &arena.allocator, .{}, .{ 2215 const name = try stmt.oneAlloc(typ, allocator, .{}, .{
2208 .id = @as(usize, 20), 2216 .id = @as(usize, 20),
2209 }); 2217 });
2210 try testing.expect(name != null); 2218 try testing.expect(name != null);
@@ -2217,7 +2225,10 @@ test "sqlite: read a single text value" {
2217 const type_info = @typeInfo(typ); 2225 const type_info = @typeInfo(typ);
2218 break :blk switch (type_info) { 2226 break :blk switch (type_info) {
2219 .Pointer => name.?, 2227 .Pointer => name.?,
2220 .Array => mem.spanZ(&(name.?)), 2228 .Array => |arr| if (arr.sentinel) |s|
2229 mem.sliceTo(&name.?, s)
2230 else
2231 mem.span(&name.?),
2221 else => @compileError("invalid type " ++ @typeName(typ)), 2232 else => @compileError("invalid type " ++ @typeName(typ)),
2222 }; 2233 };
2223 }; 2234 };
@@ -2263,6 +2274,7 @@ test "sqlite: read a single integer value" {
2263test "sqlite: read a single value into an enum backed by an integer" { 2274test "sqlite: read a single value into an enum backed by an integer" {
2264 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2275 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2265 defer arena.deinit(); 2276 defer arena.deinit();
2277 var allocator = arena.allocator();
2266 2278
2267 var db = try getTestDb(); 2279 var db = try getTestDb();
2268 try createTestTables(&db); 2280 try createTestTables(&db);
@@ -2297,7 +2309,7 @@ test "sqlite: read a single value into an enum backed by an integer" {
2297 var stmt: StatementType(.{}, query) = try db.prepare(query); 2309 var stmt: StatementType(.{}, query) = try db.prepare(query);
2298 defer stmt.deinit(); 2310 defer stmt.deinit();
2299 2311
2300 const b = try stmt.oneAlloc(IntColor, &arena.allocator, .{}, .{ 2312 const b = try stmt.oneAlloc(IntColor, allocator, .{}, .{
2301 .id = @as(usize, 10), 2313 .id = @as(usize, 10),
2302 }); 2314 });
2303 try testing.expect(b != null); 2315 try testing.expect(b != null);
@@ -2308,6 +2320,7 @@ test "sqlite: read a single value into an enum backed by an integer" {
2308test "sqlite: read a single value into an enum backed by a string" { 2320test "sqlite: read a single value into an enum backed by a string" {
2309 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2321 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2310 defer arena.deinit(); 2322 defer arena.deinit();
2323 var allocator = arena.allocator();
2311 2324
2312 var db = try getTestDb(); 2325 var db = try getTestDb();
2313 try createTestTables(&db); 2326 try createTestTables(&db);
@@ -2322,7 +2335,7 @@ test "sqlite: read a single value into an enum backed by a string" {
2322 var stmt: StatementType(.{}, query) = try db.prepare(query); 2335 var stmt: StatementType(.{}, query) = try db.prepare(query);
2323 defer stmt.deinit(); 2336 defer stmt.deinit();
2324 2337
2325 const b = try stmt.oneAlloc(TestUser.Color, &arena.allocator, .{}, .{ 2338 const b = try stmt.oneAlloc(TestUser.Color, allocator, .{}, .{
2326 .id = @as(usize, 10), 2339 .id = @as(usize, 10),
2327 }); 2340 });
2328 try testing.expect(b != null); 2341 try testing.expect(b != null);
@@ -2403,6 +2416,7 @@ test "sqlite: bind string literal" {
2403test "sqlite: bind pointer" { 2416test "sqlite: bind pointer" {
2404 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2417 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2405 defer arena.deinit(); 2418 defer arena.deinit();
2419 var allocator = arena.allocator();
2406 2420
2407 var db = try getTestDb(); 2421 var db = try getTestDb();
2408 try addTestData(&db); 2422 try addTestData(&db);
@@ -2415,7 +2429,7 @@ test "sqlite: bind pointer" {
2415 for (test_users) |test_user, i| { 2429 for (test_users) |test_user, i| {
2416 stmt.reset(); 2430 stmt.reset();
2417 2431
2418 const name = try stmt.oneAlloc([]const u8, &arena.allocator, .{}, .{&test_user.id}); 2432 const name = try stmt.oneAlloc([]const u8, allocator, .{}, .{&test_user.id});
2419 try testing.expect(name != null); 2433 try testing.expect(name != null);
2420 try testing.expectEqualStrings(test_users[i].name, name.?); 2434 try testing.expectEqualStrings(test_users[i].name, name.?);
2421 } 2435 }
@@ -2424,6 +2438,7 @@ test "sqlite: bind pointer" {
2424test "sqlite: read pointers" { 2438test "sqlite: read pointers" {
2425 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2439 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2426 defer arena.deinit(); 2440 defer arena.deinit();
2441 var allocator = arena.allocator();
2427 2442
2428 var db = try getTestDb(); 2443 var db = try getTestDb();
2429 try addTestData(&db); 2444 try addTestData(&db);
@@ -2440,7 +2455,7 @@ test "sqlite: read pointers" {
2440 age: *u32, 2455 age: *u32,
2441 weight: *f32, 2456 weight: *f32,
2442 }, 2457 },
2443 &arena.allocator, 2458 allocator,
2444 .{}, 2459 .{},
2445 .{}, 2460 .{},
2446 ); 2461 );
@@ -2510,7 +2525,7 @@ test "sqlite: statement reset" {
2510test "sqlite: statement iterator" { 2525test "sqlite: statement iterator" {
2511 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2526 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2512 defer arena.deinit(); 2527 defer arena.deinit();
2513 var allocator = &arena.allocator; 2528 var allocator = arena.allocator();
2514 2529
2515 var db = try getTestDb(); 2530 var db = try getTestDb();
2516 try addTestData(&db); 2531 try addTestData(&db);
@@ -2559,7 +2574,7 @@ test "sqlite: statement iterator" {
2559 2574
2560 for (rows.items) |row, j| { 2575 for (rows.items) |row, j| {
2561 const exp_row = expected_rows.items[j]; 2576 const exp_row = expected_rows.items[j];
2562 try testing.expectEqualStrings(exp_row.name, mem.spanZ(&row.name)); 2577 try testing.expectEqualStrings(exp_row.name, mem.sliceTo(&row.name, 0));
2563 try testing.expectEqual(exp_row.age, row.age); 2578 try testing.expectEqual(exp_row.age, row.age);
2564 } 2579 }
2565 } 2580 }
@@ -2595,7 +2610,7 @@ test "sqlite: statement iterator" {
2595test "sqlite: blob open, reopen" { 2610test "sqlite: blob open, reopen" {
2596 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2611 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2597 defer arena.deinit(); 2612 defer arena.deinit();
2598 var allocator = &arena.allocator; 2613 var allocator = arena.allocator();
2599 2614
2600 var db = try getTestDb(); 2615 var db = try getTestDb();
2601 defer db.deinit(); 2616 defer db.deinit();
@@ -2747,6 +2762,7 @@ test "sqlite: exec with diags, failing statement" {
2747test "sqlite: savepoint with no failures" { 2762test "sqlite: savepoint with no failures" {
2748 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2763 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2749 defer arena.deinit(); 2764 defer arena.deinit();
2765 var allocator = arena.allocator();
2750 2766
2751 var db = try getTestDb(); 2767 var db = try getTestDb();
2752 try addTestData(&db); 2768 try addTestData(&db);
@@ -2779,7 +2795,7 @@ test "sqlite: savepoint with no failures" {
2779 data: []const u8, 2795 data: []const u8,
2780 author_id: usize, 2796 author_id: usize,
2781 }, 2797 },
2782 &arena.allocator, 2798 allocator,
2783 .{}, 2799 .{},
2784 .{}, 2800 .{},
2785 ); 2801 );
@@ -2794,6 +2810,7 @@ test "sqlite: savepoint with no failures" {
2794test "sqlite: two nested savepoints with inner failure" { 2810test "sqlite: two nested savepoints with inner failure" {
2795 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2811 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2796 defer arena.deinit(); 2812 defer arena.deinit();
2813 var allocator = arena.allocator();
2797 2814
2798 var db = try getTestDb(); 2815 var db = try getTestDb();
2799 try addTestData(&db); 2816 try addTestData(&db);
@@ -2831,7 +2848,7 @@ test "sqlite: two nested savepoints with inner failure" {
2831 data: []const u8, 2848 data: []const u8,
2832 author_id: usize, 2849 author_id: usize,
2833 }, 2850 },
2834 &arena.allocator, 2851 allocator,
2835 .{}, 2852 .{},
2836 .{}, 2853 .{},
2837 ); 2854 );
@@ -2843,6 +2860,7 @@ test "sqlite: two nested savepoints with inner failure" {
2843test "sqlite: two nested savepoints with outer failure" { 2860test "sqlite: two nested savepoints with outer failure" {
2844 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2861 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2845 defer arena.deinit(); 2862 defer arena.deinit();
2863 var allocator = arena.allocator();
2846 2864
2847 var db = try getTestDb(); 2865 var db = try getTestDb();
2848 try addTestData(&db); 2866 try addTestData(&db);
@@ -2869,7 +2887,7 @@ test "sqlite: two nested savepoints with outer failure" {
2869 var stmt = try db.prepare("SELECT 1 FROM article"); 2887 var stmt = try db.prepare("SELECT 1 FROM article");
2870 defer stmt.deinit(); 2888 defer stmt.deinit();
2871 2889
2872 var rows = try stmt.all(usize, &arena.allocator, .{}, .{}); 2890 var rows = try stmt.all(usize, allocator, .{}, .{});
2873 try testing.expectEqual(@as(usize, 0), rows.len); 2891 try testing.expectEqual(@as(usize, 0), rows.len);
2874} 2892}
2875 2893
@@ -2877,7 +2895,7 @@ fn getTestDb() !Db {
2877 var buf: [1024]u8 = undefined; 2895 var buf: [1024]u8 = undefined;
2878 var fba = std.heap.FixedBufferAllocator.init(&buf); 2896 var fba = std.heap.FixedBufferAllocator.init(&buf);
2879 2897
2880 var mode = dbMode(&fba.allocator); 2898 var mode = dbMode(fba.allocator());
2881 2899
2882 return try Db.init(.{ 2900 return try Db.init(.{
2883 .open_flags = .{ 2901 .open_flags = .{
@@ -2888,7 +2906,7 @@ fn getTestDb() !Db {
2888 }); 2906 });
2889} 2907}
2890 2908
2891fn tmpDbPath(allocator: *mem.Allocator) ![:0]const u8 { 2909fn tmpDbPath(allocator: mem.Allocator) ![:0]const u8 {
2892 const tmp_dir = testing.tmpDir(.{}); 2910 const tmp_dir = testing.tmpDir(.{});
2893 2911
2894 const path = try std.fs.path.join(allocator, &[_][]const u8{ 2912 const path = try std.fs.path.join(allocator, &[_][]const u8{
@@ -2902,7 +2920,7 @@ fn tmpDbPath(allocator: *mem.Allocator) ![:0]const u8 {
2902 return allocator.dupeZ(u8, path); 2920 return allocator.dupeZ(u8, path);
2903} 2921}
2904 2922
2905fn dbMode(allocator: *mem.Allocator) Db.Mode { 2923fn dbMode(allocator: mem.Allocator) Db.Mode {
2906 return if (build_options.in_memory) blk: { 2924 return if (build_options.in_memory) blk: {
2907 break :blk .{ .Memory = {} }; 2925 break :blk .{ .Memory = {} };
2908 } else blk: { 2926 } else blk: {
@@ -2922,11 +2940,11 @@ const MyData = struct {
2922 2940
2923 const BaseType = []const u8; 2941 const BaseType = []const u8;
2924 2942
2925 pub fn bindField(self: MyData, allocator: *std.mem.Allocator) !BaseType { 2943 pub fn bindField(self: MyData, allocator: mem.Allocator) !BaseType {
2926 return try std.fmt.allocPrint(allocator, "{}", .{std.fmt.fmtSliceHexLower(&self.data)}); 2944 return try std.fmt.allocPrint(allocator, "{}", .{std.fmt.fmtSliceHexLower(&self.data)});
2927 } 2945 }
2928 2946
2929 pub fn readField(alloc: *std.mem.Allocator, value: BaseType) !MyData { 2947 pub fn readField(alloc: mem.Allocator, value: BaseType) !MyData {
2930 _ = alloc; 2948 _ = alloc;
2931 2949
2932 var result = [_]u8{0} ** 16; 2950 var result = [_]u8{0} ** 16;
@@ -2942,6 +2960,7 @@ const MyData = struct {
2942test "sqlite: bind custom type" { 2960test "sqlite: bind custom type" {
2943 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2961 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2944 defer arena.deinit(); 2962 defer arena.deinit();
2963 var allocator = arena.allocator();
2945 2964
2946 var db = try getTestDb(); 2965 var db = try getTestDb();
2947 try addTestData(&db); 2966 try addTestData(&db);
@@ -2953,7 +2972,7 @@ test "sqlite: bind custom type" {
2953 { 2972 {
2954 // insertion 2973 // insertion
2955 var stmt = try db.prepare("INSERT INTO article(data) VALUES(?)"); 2974 var stmt = try db.prepare("INSERT INTO article(data) VALUES(?)");
2956 try stmt.execAlloc(&arena.allocator, .{}, .{my_data}); 2975 try stmt.execAlloc(allocator, .{}, .{my_data});
2957 } 2976 }
2958 { 2977 {
2959 // reading back 2978 // reading back
@@ -2967,7 +2986,7 @@ test "sqlite: bind custom type" {
2967 is_published: bool, 2986 is_published: bool,
2968 }; 2987 };
2969 2988
2970 const row = try stmt.oneAlloc(Article, &arena.allocator, .{}, .{}); 2989 const row = try stmt.oneAlloc(Article, allocator, .{}, .{});
2971 2990
2972 try testing.expect(row != null); 2991 try testing.expect(row != null);
2973 try testing.expectEqualSlices(u8, &my_data.data, &row.?.data.data); 2992 try testing.expectEqualSlices(u8, &my_data.data, &row.?.data.data);
@@ -2977,6 +2996,7 @@ test "sqlite: bind custom type" {
2977test "sqlite: prepareDynamic" { 2996test "sqlite: prepareDynamic" {
2978 var arena = std.heap.ArenaAllocator.init(testing.allocator); 2997 var arena = std.heap.ArenaAllocator.init(testing.allocator);
2979 defer arena.deinit(); 2998 defer arena.deinit();
2999 var allocator = arena.allocator();
2980 3000
2981 var db = try getTestDb(); 3001 var db = try getTestDb();
2982 try addTestData(&db); 3002 try addTestData(&db);
@@ -2996,7 +3016,7 @@ test "sqlite: prepareDynamic" {
2996 stmt.reset(); 3016 stmt.reset();
2997 3017
2998 { 3018 {
2999 var iter = try stmt.iteratorAlloc(usize, &arena.allocator, .{ .age = 33 }); 3019 var iter = try stmt.iteratorAlloc(usize, allocator, .{ .age = 33 });
3000 3020
3001 const id = try iter.next(.{}); 3021 const id = try iter.next(.{});
3002 try testing.expect(id != null); 3022 try testing.expect(id != null);
@@ -3006,7 +3026,7 @@ test "sqlite: prepareDynamic" {
3006 stmt.reset(); 3026 stmt.reset();
3007 3027
3008 { 3028 {
3009 var iter = try stmt.iteratorAlloc(usize, &arena.allocator, .{33}); 3029 var iter = try stmt.iteratorAlloc(usize, allocator, .{33});
3010 3030
3011 const id = try iter.next(.{}); 3031 const id = try iter.next(.{});
3012 try testing.expect(id != null); 3032 try testing.expect(id != null);
@@ -3017,6 +3037,7 @@ test "sqlite: prepareDynamic" {
3017test "sqlite: oneDynamic" { 3037test "sqlite: oneDynamic" {
3018 var arena = std.heap.ArenaAllocator.init(testing.allocator); 3038 var arena = std.heap.ArenaAllocator.init(testing.allocator);
3019 defer arena.deinit(); 3039 defer arena.deinit();
3040 var allocator = arena.allocator();
3020 3041
3021 var db = try getTestDb(); 3042 var db = try getTestDb();
3022 try addTestData(&db); 3043 try addTestData(&db);
@@ -3050,7 +3071,7 @@ test "sqlite: oneDynamic" {
3050 { 3071 {
3051 const id = try db.oneDynamicAlloc( 3072 const id = try db.oneDynamicAlloc(
3052 usize, 3073 usize,
3053 &arena.allocator, 3074 allocator,
3054 "SELECT id FROM user WHERE age = ?", 3075 "SELECT id FROM user WHERE age = ?",
3055 .{ .diags = &diags }, 3076 .{ .diags = &diags },
3056 .{ .age = 33 }, 3077 .{ .age = 33 },
@@ -3062,7 +3083,7 @@ test "sqlite: oneDynamic" {
3062 { 3083 {
3063 const id = try db.oneDynamicAlloc( 3084 const id = try db.oneDynamicAlloc(
3064 usize, 3085 usize,
3065 &arena.allocator, 3086 allocator,
3066 "SELECT id FROM user WHERE age = ?", 3087 "SELECT id FROM user WHERE age = ?",
3067 .{ .diags = &diags }, 3088 .{ .diags = &diags },
3068 .{33}, 3089 .{33},